Spotted by ASAN after a crash. It's possible that this is related to multiple LogMsg instances being created with the same gchar* -- but as far as I can tell, std::string(const char*) should always make a copy. Otherwise, this may be related to the struct not following the rule of 3/5/0. Either way, it looks like both thread T0 and T14 are trying to run the destructor for the same LogMsg instance, which results in the double-free.
==750327==ERROR: AddressSanitizer: attempting double-free on 0x7baca2e06c90 in thread T14:
#0 0x7f7ca5f1bb1b in operator delete(void*, unsigned long) ../../../../src/libsanitizer/asan/asan_new_delete.cpp:155
#1 0x55dbabe2cab5 in std::__new_allocator<char>::deallocate(char*, unsigned long) /usr/include/c++/15/bits/new_allocator.h:172
#2 0x55dbabe2cab5 in std::allocator_traits<std::allocator<char> >::deallocate(std::allocator<char>&, char*, unsigned long) /usr/include/c++/15/bits/alloc_traits.h:649
#3 0x55dbabe2cab5 in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_destroy(unsigned long) /usr/include/c++/15/bits/basic_string.h:305
#4 0x55dbabe2cab5 in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_dispose() /usr/include/c++/15/bits/basic_string.h:299
#5 0x55dbabf6c51f in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string() /usr/include/c++/15/bits/basic_string.h:896
#6 0x55dbabf6c51f in LogMsg::~LogMsg() ../src/logwindow.cc:498
#7 0x55dbabf6c51f in void std::_Destroy<LogMsg>(LogMsg*) /usr/include/c++/15/bits/stl_construct.h:166
#8 0x55dbabf6c51f in void std::_Destroy<LogMsg*>(LogMsg*, LogMsg*) /usr/include/c++/15/bits/stl_construct.h:226
#9 0x55dbabf6c51f in void std::_Destroy<LogMsg*, LogMsg>(LogMsg*, LogMsg*, std::allocator<LogMsg>&) /usr/include/c++/15/bits/alloc_traits.h:1045
#10 0x55dbabf6c51f in std::deque<LogMsg, std::allocator<LogMsg> >::_M_destroy_data_aux(std::_Deque_iterator<LogMsg, LogMsg&, LogMsg*>, std::_Deque_iterator<LogMsg, LogMsg&, LogMsg*>) /usr/include/c++/15/bits/deque.tcc:1041
#11 0x55dbabf6c7d9 in std::deque<LogMsg, std::allocator<LogMsg> >::_M_destroy_data(std::_Deque_iterator<LogMsg, LogMsg&, LogMsg*>, std::_Deque_iterator<LogMsg, LogMsg&, LogMsg*>, std::allocator<LogMsg> const&) /usr/include/c++/15/bits/stl_deque.h:2204
#12 0x55dbabf6cb21 in std::deque<LogMsg, std::allocator<LogMsg> >::~deque() /usr/include/c++/15/bits/stl_deque.h:1043
#13 0x7f7ca424b3a0 in __run_exit_handlers stdlib/exit.c:118
#14 0x7f7ca424b46b in __GI_exit stdlib/exit.c:148
#15 0x55dbabf71df4 in sig_handler_cb ../src/main.cc:274
#16 0x7f7ca4248e2f (/usr/lib/x86_64-linux-gnu/libc.so.6+0x40e2f) (BuildId: e0715e6b2fc508102cc2100d3d25a1aa4eb676f9)
#17 0x7f7ca508beb8 in jpeg_fill_bit_buffer src/jdhuff.c:310
#18 0x7f7ca509b71b in decode_mcu_DC_first src/jdphuff.c:329
#19 0x7f7ca507f4c6 in consume_data src/wrapper/../jdcoefct.c:236
#20 0x7f7ca507af80 in jpeg_start_decompress src/wrapper/../jdapistd.c:74
#21 0x55dbac072253 in ImageLoaderJpeg::write(unsigned char const*, unsigned long&, unsigned long, _GError**) ../src/image-load-jpeg.cc:360
#22 0x55dbabf12b0f in image_loader_begin ../src/image-load.cc:858
#23 0x55dbabf13214 in image_loader_thread_run ../src/image-load.cc:1151
#24 0x7f7ca51f2e29 (/usr/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x92e29) (BuildId: fa948a74679999d95c17c8bbbcc0dfd3752f17aa)
#25 0x7f7ca51f2675 (/usr/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x92675) (BuildId: fa948a74679999d95c17c8bbbcc0dfd3752f17aa)
#26 0x7f7ca5e5c0f5 in asan_thread_start ../../../../src/libsanitizer/asan/asan_interceptors.cpp:239
#27 0x7f7ca429dda8 in start_thread nptl/pthread_create.c:448
#28 0x7f7ca431ce07 in __clone3 ../sysdeps/unix/sysv/linux/x86_64/clone3.S:78
0x7baca2e06c90 is located 0 bytes inside of 28-byte region [0x7baca2e06c90,0x7baca2e06cac)
freed by thread T0 here:
#0 0x7f7ca5f1bb1b in operator delete(void*, unsigned long) ../../../../src/libsanitizer/asan/asan_new_delete.cpp:155
#1 0x55dbabe2cab5 in std::__new_allocator<char>::deallocate(char*, unsigned long) /usr/include/c++/15/bits/new_allocator.h:172
#2 0x55dbabe2cab5 in std::allocator_traits<std::allocator<char> >::deallocate(std::allocator<char>&, char*, unsigned long) /usr/include/c++/15/bits/alloc_traits.h:649
#3 0x55dbabe2cab5 in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_destroy(unsigned long) /usr/include/c++/15/bits/basic_string.h:305
#4 0x55dbabe2cab5 in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_dispose() /usr/include/c++/15/bits/basic_string.h:299
#5 0x55dbabf6c577 in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string() /usr/include/c++/15/bits/basic_string.h:896
#6 0x55dbabf6c577 in LogMsg::~LogMsg() ../src/logwindow.cc:498
#7 0x55dbabf6c577 in void std::_Destroy<LogMsg>(LogMsg*) /usr/include/c++/15/bits/stl_construct.h:166
#8 0x55dbabf6c577 in void std::_Destroy<LogMsg*>(LogMsg*, LogMsg*) /usr/include/c++/15/bits/stl_construct.h:226
#9 0x55dbabf6c577 in void std::_Destroy<LogMsg*, LogMsg>(LogMsg*, LogMsg*, std::allocator<LogMsg>&) /usr/include/c++/15/bits/alloc_traits.h:1045
#10 0x55dbabf6c577 in std::deque<LogMsg, std::allocator<LogMsg> >::_M_destroy_data_aux(std::_Deque_iterator<LogMsg, LogMsg&, LogMsg*>, std::_Deque_iterator<LogMsg, LogMsg&, LogMsg*>) /usr/include/c++/15/bits/deque.tcc:1045
#11 0x55dbabf6c7d9 in std::deque<LogMsg, std::allocator<LogMsg> >::_M_destroy_data(std::_Deque_iterator<LogMsg, LogMsg&, LogMsg*>, std::_Deque_iterator<LogMsg, LogMsg&, LogMsg*>, std::allocator<LogMsg> const&) /usr/include/c++/15/bits/stl_deque.h:2204
#12 0x55dbabf6ce7d in std::deque<LogMsg, std::allocator<LogMsg> >::_M_erase_at_end(std::_Deque_iterator<LogMsg, LogMsg&, LogMsg*>) /usr/include/c++/15/bits/stl_deque.h:2221
#13 0x55dbabf6feb7 in std::deque<LogMsg, std::allocator<LogMsg> >::resize(unsigned long) /usr/include/c++/15/bits/stl_deque.h:1361
#14 0x55dbabf6afa6 in log_window_append(char const*, LogType) ../src/logwindow.cc:534
#15 0x55dbabe80e84 in log_normal_cb ../src/debug.cc:84
#16 0x7f7ca51bc68d (/usr/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x5c68d) (BuildId: fa948a74679999d95c17c8bbbcc0dfd3752f17aa)
previously allocated by thread T0 here:
#0 0x7f7ca5f1abbb in operator new(unsigned long) ../../../../src/libsanitizer/asan/asan_new_delete.cpp:86
#1 0x55dbabe2cb1b in std::__new_allocator<char>::allocate(unsigned long, void const*) /usr/include/c++/15/bits/new_allocator.h:151
#2 0x55dbabe2cb1b in std::allocator_traits<std::allocator<char> >::allocate(std::allocator<char>&, unsigned long) /usr/include/c++/15/bits/alloc_traits.h:614
#3 0x55dbabe2cb1b in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_S_allocate(std::allocator<char>&, unsigned long) /usr/include/c++/15/bits/basic_string.h:142
#4 0x55dbabe2cb1b in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_create(unsigned long&, unsigned long) /usr/include/c++/15/bits/basic_string.tcc:164
#5 0x55dbabe2f9e7 in void std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_construct<char const*>(char const*, char const*, std::forward_iterator_tag) /usr/include/c++/15/bits/basic_string.tcc:235
#6 0x55dbabe2fc21 in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string<std::allocator<char> >(char const*, std::allocator<char> const&) /usr/include/c++/15/bits/basic_string.h:714
#7 0x55dbabf6f3f0 in LogMsg::LogMsg(char const*, LogType) ../src/logwindow.cc:501
#8 0x55dbabf6f3f0 in void std::__new_allocator<LogMsg>::construct<LogMsg, char const*&, LogType&>(LogMsg*, char const*&, LogType&) /usr/include/c++/15/bits/new_allocator.h:191
#9 0x55dbabf6f3f0 in void std::allocator_traits<std::allocator<LogMsg> >::construct<LogMsg, char const*&, LogType&>(std::allocator<LogMsg>&, LogMsg*, char const*&, LogType&) /usr/include/c++/15/bits/alloc_traits.h:674
#10 0x55dbabf6f3f0 in LogMsg& std::deque<LogMsg, std::allocator<LogMsg> >::emplace_front<char const*&, LogType&>(char const*&, LogType&) /usr/include/c++/15/bits/deque.tcc:145
#11 0x55dbabf6af0f in log_window_append(char const*, LogType) ../src/logwindow.cc:528
#12 0x55dbabe80dbe in log_msg_cb ../src/debug.cc:54
#13 0x7f7ca51bc68d (/usr/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x5c68d) (BuildId: fa948a74679999d95c17c8bbbcc0dfd3752f17aa)
Thread T14 created by T2 here:
#0 0x7f7ca5f11612 in pthread_create ../../../../src/libsanitizer/asan/asan_interceptors.cpp:250
#1 0x7f7ca51f11c8 (/usr/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x911c8) (BuildId: fa948a74679999d95c17c8bbbcc0dfd3752f17aa)
Thread T2 created by T0 here:
#0 0x7f7ca5f11612 in pthread_create ../../../../src/libsanitizer/asan/asan_interceptors.cpp:250
#1 0x7f7ca51f11c8 (/usr/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x911c8) (BuildId: fa948a74679999d95c17c8bbbcc0dfd3752f17aa)
SUMMARY: AddressSanitizer: double-free ../src/logwindow.cc:498 in LogMsg::~LogMsg()
Setup (please complete the following information):
Spotted by ASAN after a crash. It's possible that this is related to multiple LogMsg instances being created with the same
gchar*-- but as far as I can tell,std::string(const char*)should always make a copy. Otherwise, this may be related to the struct not following the rule of 3/5/0. Either way, it looks like both thread T0 and T14 are trying to run the destructor for the same LogMsg instance, which results in the double-free.Code snippet: