LithApp / Lith

Multiplatform, mobile-focused WeeChat relay client
https://lith.app
GNU General Public License v2.0
75 stars 7 forks source link

Don't delete a std::function that's being executed #86

Closed syyyr closed 3 years ago

syyyr commented 3 years ago

I'm not sure about this new/delete approach, but this fixes a segfault. The segfault actually happens inside the other lambda. I am too lazy to figure out the exact reason, but I would think that deleting the testSettingsReady lambda deletes its = capture, which means that the other lambda also gets deleted, which then means that the this capture is also not valid and this this causes the segfault.

It is unfortunate that this kind of code exists, but oh well.

$ ./Lith 
=================================================================
==116557==ERROR: AddressSanitizer: heap-use-after-free on address 0x6030003b3510 at pc 0x56385f01db9f bp 0x7ffecfcdd7f0 sp 0x7ffecfcdd7e0
READ of size 8 at 0x6030003b3510 thread T0
    #0 0x56385f01db9e in operator() ../src/settings.cpp:34
    #1 0x56385f01e0e6 in operator() ../src/settings.cpp:51
    #2 0x56385f02054d in __invoke_impl<void, Settings::Settings(QObject*)::<lambda()>&> /usr/include/c++/10.2.0/bits/invoke.h:60
    #3 0x56385f0203fa in __invoke_r<void, Settings::Settings(QObject*)::<lambda()>&> /usr/include/c++/10.2.0/bits/invoke.h:110
    #4 0x56385f020198 in _M_invoke /usr/include/c++/10.2.0/bits/std_function.h:291
    #5 0x56385f0271f3 in std::function<void ()>::operator()() const /usr/include/c++/10.2.0/bits/std_function.h:622
    #6 0x56385f01f60a in Settings::Settings(QObject*) ../src/settings.cpp:56
    #7 0x56385efb1c18 in Lith::Lith(QObject*) ../src/lith.cpp:127
    #8 0x56385efb08d9 in Lith::instance() ../src/lith.cpp:36
    #9 0x56385efd79db in main ../src/main.cpp:61
    #10 0x7f36b0275b24 in __libc_start_main (/usr/lib/libc.so.6+0x27b24)
    #11 0x56385efb07dd in _start (/home/vk/git/Lith/build/Lith+0xee7dd)

0x6030003b3510 is located 16 bytes inside of 24-byte region [0x6030003b3500,0x6030003b3518)
freed by thread T0 here:
    #0 0x7f36b2951009 in operator delete(void*, unsigned long) /build/gcc/src/gcc/libsanitizer/asan/asan_new_delete.cpp:172
    #1 0x56385f020704 in _M_destroy /usr/include/c++/10.2.0/bits/std_function.h:176
    #2 0x56385f0204f9 in _M_manager /usr/include/c++/10.2.0/bits/std_function.h:200
    #3 0x56385f02024b in _M_manager /usr/include/c++/10.2.0/bits/std_function.h:283
    #4 0x56385f026e25 in std::_Function_base::~_Function_base() /usr/include/c++/10.2.0/bits/std_function.h:245
    #5 0x56385f026eab in std::function<void ()>::~function() /usr/include/c++/10.2.0/bits/std_function.h:303
    #6 0x56385f01e0c6 in operator() ../src/settings.cpp:50
    #7 0x56385f02054d in __invoke_impl<void, Settings::Settings(QObject*)::<lambda()>&> /usr/include/c++/10.2.0/bits/invoke.h:60
    #8 0x56385f0203fa in __invoke_r<void, Settings::Settings(QObject*)::<lambda()>&> /usr/include/c++/10.2.0/bits/invoke.h:110
    #9 0x56385f020198 in _M_invoke /usr/include/c++/10.2.0/bits/std_function.h:291
    #10 0x56385f0271f3 in std::function<void ()>::operator()() const /usr/include/c++/10.2.0/bits/std_function.h:622
    #11 0x56385f01f60a in Settings::Settings(QObject*) ../src/settings.cpp:56
    #12 0x56385efb1c18 in Lith::Lith(QObject*) ../src/lith.cpp:127
    #13 0x56385efb08d9 in Lith::instance() ../src/lith.cpp:36
    #14 0x56385efd79db in main ../src/main.cpp:61
    #15 0x7f36b0275b24 in __libc_start_main (/usr/lib/libc.so.6+0x27b24)

previously allocated by thread T0 here:
    #0 0x7f36b294ff41 in operator new(unsigned long) /build/gcc/src/gcc/libsanitizer/asan/asan_new_delete.cpp:99
    #1 0x56385f020282 in _M_init_functor /usr/include/c++/10.2.0/bits/std_function.h:237
    #2 0x56385f020175 in _M_init_functor /usr/include/c++/10.2.0/bits/std_function.h:208
    #3 0x56385f020025 in function<Settings::Settings(QObject*)::<lambda()> > /usr/include/c++/10.2.0/bits/std_function.h:609
    #4 0x56385f01fe79 in operator=<Settings::Settings(QObject*)::<lambda()> > /usr/include/c++/10.2.0/bits/std_function.h:459
    #5 0x56385f01f5e1 in Settings::Settings(QObject*) ../src/settings.cpp:55
    #6 0x56385efb1c18 in Lith::Lith(QObject*) ../src/lith.cpp:127
    #7 0x56385efb08d9 in Lith::instance() ../src/lith.cpp:36
    #8 0x56385efd79db in main ../src/main.cpp:61
    #9 0x7f36b0275b24 in __libc_start_main (/usr/lib/libc.so.6+0x27b24)

SUMMARY: AddressSanitizer: heap-use-after-free ../src/settings.cpp:34 in operator()
Shadow bytes around the buggy address:
  0x0c068006e650: fa fa 00 00 00 00 fa fa fd fd fd fa fa fa fd fd
  0x0c068006e660: fd fd fa fa 00 00 04 fa fa fa 00 00 04 fa fa fa
  0x0c068006e670: 00 00 05 fa fa fa 00 00 04 fa fa fa 00 00 04 fa
  0x0c068006e680: fa fa fd fd fd fa fa fa fd fd fd fd fa fa fd fd
  0x0c068006e690: fd fa fa fa fd fd fd fa fa fa fd fd fd fd fa fa
=>0x0c068006e6a0: fd fd[fd]fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c068006e6b0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c068006e6c0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c068006e6d0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c068006e6e0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c068006e6f0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
  Shadow gap:              cc
==116557==ABORTING