There are a number of test cases where a thread sanitizer built on host=x86_64-linux-gnu, using gcc 12.2.0 (Debian 12.2.0-14), reports race conditons. gdb.base/align-c++.exp gdb.base/align-c.exp gdb.base/batch-preserve-term-settings.exp gdb.base/break.exp (several times) gdb.base/cached-source-file.exp gdb.base/chng-syms.exp ... etc. etc.
Created attachment 15503 [details] tsan output from gdb.base/align-c++.exp
Created attachment 15504 [details] tsan output from gdb.base/align-c.exp
Created attachment 15505 [details] tsan output from gdb.base/batch-preserve-term-settings.exp
Created attachment 15506 [details] tsan output from gdb.base/break.exp These are some samples how the tsan reports look like They are all very similar to those.
Can you try the dwarf synchronous change for this one? https://sourceware.org/pipermail/gdb-patches/2024-May/209267.html
Confirmed. The reported race conditions are no longer reproducible with your patch.
I suspect from the stack trace that this is happening because cooked_index::full_name does: const char *local_name = for_main ? name : canonical; but the finalizing code sets canonical: entry->canonical = entry->name; However I think this seems like an erroneous report because canonical shouldn't be usable from the "main" path, because that code always passes for_main=true: return entry->full_name (obstack, true);
This is one sample of that trace with your latest patch applied: (gdb) set width 0 (gdb) dir Reinitialize source path to empty? (y or n) y Source directories searched: $cdir:$cwd (gdb) dir /home/ed/gnu/gdb-build-y/gdb/testsuite/../../../binutils-gdb/gdb/testsuite/gdb.base Source directories searched: /home/ed/gnu/gdb-build-y/gdb/testsuite/../../../binutils-gdb/gdb/testsuite/gdb.base:$cdir:$cwd (gdb) kill The program is not being run. (gdb) file /home/ed/gnu/gdb-build-y/gdb/testsuite/outputs/gdb.base/annota1/annota1 Reading symbols from /home/ed/gnu/gdb-build-y/gdb/testsuite/outputs/gdb.base/annota1/annota1... (gdb) set height 0 ================== WARNING: ThreadSanitizer: data race (pid=29546) Read of size 8 at 0x7b8000020288 by main thread: #0 cooked_index_entry::full_name(obstack*, bool) const ../../binutils-gdb/gdb/dwarf2/cooked-index.c:220 (gdb+0x31c114) #1 cooked_index::get_main_name(obstack*, language*) const ../../binutils-gdb/gdb/dwarf2/cooked-index.c:735 (gdb+0x31d549) #2 cooked_index_worker::wait(cooked_state, bool) ../../binutils-gdb/gdb/dwarf2/cooked-index.c:559 (gdb+0x31d549) #3 cooked_index::wait(cooked_state, bool) ../../binutils-gdb/gdb/dwarf2/cooked-index.c:631 (gdb+0x31e085) #4 cooked_index_functions::wait(objfile*, bool) ../../binutils-gdb/gdb/dwarf2/cooked-index.h:729 (gdb+0x364e0c) #5 cooked_index_functions::compute_main_name(objfile*) ../../binutils-gdb/gdb/dwarf2/cooked-index.h:806 (gdb+0x364e0c) #6 objfile::compute_main_name() ../../binutils-gdb/gdb/symfile-debug.c:461 (gdb+0x69d904) #7 find_main_name ../../binutils-gdb/gdb/symtab.c:6503 (gdb+0x6b8b4c) #8 main_language() ../../binutils-gdb/gdb/symtab.c:6608 (gdb+0x6c71a3) #9 set_initial_language_callback ../../binutils-gdb/gdb/symfile.c:1634 (gdb+0x69ffdf) #10 get_current_language() ../../binutils-gdb/gdb/language.c:96 (gdb+0x4c9aaf) #11 parse_exp_in_context ../../binutils-gdb/gdb/parse.c:415 (gdb+0x5a7594) #12 parse_expression(char const*, innermost_block_tracker*, enum_flags<parser_flag>) ../../binutils-gdb/gdb/parse.c:478 (gdb+0x5a7dbe) #13 parse_and_eval_long(char const*) ../../binutils-gdb/gdb/eval.c:63 (gdb+0x3d61ca) #14 parse_cli_var_integer(var_types, literal_def const*, char const**, bool) ../../binutils-gdb/gdb/cli/cli-setshow.c:232 (gdb+0x2911d8) #15 do_set_command(char const*, int, cmd_list_element*) ../../binutils-gdb/gdb/cli/cli-setshow.c:421 (gdb+0x293144) #16 execute_command(char const*, int) ../../binutils-gdb/gdb/top.c:562 (gdb+0x732693) #17 command_handler(char const*) ../../binutils-gdb/gdb/event-top.c:580 (gdb+0x3e128d) #18 command_line_handler(std::unique_ptr<char, gdb::xfree_deleter<char> >&&) ../../binutils-gdb/gdb/event-top.c:816 (gdb+0x3e3304) #19 gdb_rl_callback_handler ../../binutils-gdb/gdb/event-top.c:272 (gdb+0x3e0b67) #20 rl_callback_read_char ../../../binutils-gdb/readline/readline/callback.c:290 (gdb+0x80f4e3) #21 gdb_rl_callback_read_char_wrapper_noexcept ../../binutils-gdb/gdb/event-top.c:197 (gdb+0x3e054d) #22 gdb_rl_callback_read_char_wrapper ../../binutils-gdb/gdb/event-top.c:236 (gdb+0x3e08ae) #23 stdin_event_handler ../../binutils-gdb/gdb/ui.c:154 (gdb+0x75a4ff) #24 handle_file_event ../../binutils-gdb/gdbsupport/event-loop.cc:551 (gdb+0x9ce523) #25 gdb_wait_for_event ../../binutils-gdb/gdbsupport/event-loop.cc:672 (gdb+0x9cec09) #26 gdb_do_one_event(int) ../../binutils-gdb/gdbsupport/event-loop.cc:263 (gdb+0x9cf5ed) #27 start_event_loop ../../binutils-gdb/gdb/main.c:401 (gdb+0x527329) #28 captured_command_loop ../../binutils-gdb/gdb/main.c:465 (gdb+0x527329) #29 gdb_wait_for_event ../../binutils-gdb/gdbsupport/event-loop.cc:672 (gdb+0x9cec09) #30 gdb_do_one_event(int) ../../binutils-gdb/gdbsupport/event-loop.cc:263 (gdb+0x9cf5ed) #31 start_event_loop ../../binutils-gdb/gdb/main.c:401 (gdb+0x527329) #32 captured_command_loop ../../binutils-gdb/gdb/main.c:465 (gdb+0x527329) #33 captured_main ../../binutils-gdb/gdb/main.c:1338 (gdb+0x52b074) #34 gdb_main(captured_main_args*) ../../binutils-gdb/gdb/main.c:1357 (gdb+0x52b074) #35 main ../../binutils-gdb/gdb/gdb.c:38 (gdb+0x1162e2) Previous write of size 8 at 0x7b8000020288 by thread T4: #0 cooked_index_shard::finalize(parent_map_map const*) ../../binutils-gdb/gdb/dwarf2/cooked-index.c:409 (gdb+0x31f6f3) #1 operator() ../../binutils-gdb/gdb/dwarf2/cooked-index.c:663 (gdb+0x31f832) #2 __invoke_impl<void, cooked_index::set_contents(vec_type&&, deferred_warnings*, const parent_map_map*)::<lambda()>&> /usr/include/c++/12/bits/invoke.h:61 (gdb+0x31f832) #3 __invoke_r<void, cooked_index::set_contents(vec_type&&, deferred_warnings*, const parent_map_map*)::<lambda()>&> /usr/include/c++/12/bits/invoke.h:111 (gdb+0x31f832) #4 _M_invoke /usr/include/c++/12/bits/std_function.h:290 (gdb+0x31f832) #5 std::function<void ()>::operator()() const /usr/include/c++/12/bits/std_function.h:591 (gdb+0x9d88f5) #6 operator() ../../binutils-gdb/gdbsupport/task-group.cc:68 (gdb+0x9d88f5) #7 __invoke_impl<void, gdb::task_group::impl::start()::<lambda()>&> /usr/include/c++/12/bits/invoke.h:61 (gdb+0x9d88f5) #8 __invoke_r<void, gdb::task_group::impl::start()::<lambda()>&> /usr/include/c++/12/bits/invoke.h:111 (gdb+0x9d88f5) #9 _M_invoke /usr/include/c++/12/bits/std_function.h:290 (gdb+0x9d88f5) #10 std::function<void ()>::operator()() const /usr/include/c++/12/bits/std_function.h:591 (gdb+0x321099) #11 void std::__invoke_impl<void, std::function<void ()>&>(std::__invoke_other, std::function<void ()>&) /usr/include/c++/12/bits/invoke.h:61 (gdb+0x321099) #12 std::enable_if<is_invocable_r_v<void, std::function<void ()>&>, void>::type std::__invoke_r<void, std::function<void ()>&>(std::function<void ()>&) /usr/include/c++/12/bits/invoke.h:111 (gdb+0x321099) #13 std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run()::{lambda()#1}::operator()() const /usr/include/c++/12/future:1469 (gdb+0x321099) #14 std::__future_base::_Task_setter<std::unique_ptr<std::__future_base::_Result<void>, std::__future_base::_Result_base::_Deleter>, std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run()::{lambda()#1}, void>::operator()() const /usr/include/c++/12/future:1410 (gdb+0x321099) #15 std::unique_ptr<std::__future_base::_Result<void>, std::__future_base::_Result_base::_Deleter> std::__invoke_impl<std::unique_ptr<std::__future_base::_Result<void>, std::__future_base::_Result_base::_Deleter>, std::__future_base::_Task_setter<std::unique_ptr<std::__future_base::_Result<void>, std::__future_base::_Result_base::_Deleter>, std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run()::{lambda()#1}, void>&>(std::__invoke_other, std::__future_base::_Task_setter<std::unique_ptr<std::__future_base::_Result<void>, std::__future_base::_Result_base::_Deleter>, std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run()::{lambda()#1}, void>&) /usr/include/c++/12/bits/invoke.h:61 (gdb+0x321099) #16 std::enable_if<is_invocable_r_v<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter>, std::__future_base::_Task_setter<std::unique_ptr<std::__future_base::_Result<void>, std::__future_base::_Result_base::_Deleter>, std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run()::{lambda()#1}, void>&>, std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> >::type std::__invoke_r<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter>, std::__future_base::_Task_setter<std::unique_ptr<std::__future_base::_Result<void>, std::__future_base::_Result_base::_Deleter>, std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run()::{lambda()#1}, void>&>(std::__future_base::_Task_setter<std::unique_ptr<std::__future_base::_Result<void>, std::__future_base::_Result_base::_Deleter>, std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run()::{lambda()#1}, void>&) /usr/include/c++/12/bits/invoke.h:116 (gdb+0x321099) #17 std::_Function_handler<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> (), std::__future_base::_Task_setter<std::unique_ptr<std::__future_base::_Result<void>, std::__future_base::_Result_base::_Deleter>, std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run()::{lambda()#1}, void> >::_M_invoke(std::_Any_data const&) /usr/include/c++/12/bits/std_function.h:291 (gdb+0x321099) #18 std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>::operator()() const /usr/include/c++/12/bits/std_function.h:591 (gdb+0x3214c9) #19 std::__future_base::_State_baseV2::_M_do_set(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*) /usr/include/c++/12/future:572 (gdb+0x3214c9) #20 void std::__invoke_impl<void, void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::__invoke_memfun_deref, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&) /usr/include/c++/12/bits/invoke.h:74 (gdb+0x320e30) #21 std::__invoke_result<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>::type std::__invoke<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&) /usr/include/c++/12/bits/invoke.h:96 (gdb+0x320e30) #22 std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&)::{lambda()#1}::operator()() const /usr/include/c++/12/mutex:852 (gdb+0x320e30) #23 std::once_flag::_Prepare_execution::_Prepare_execution<std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&)::{lambda()#1}>(void (std::__future_base::_State_baseV2::*&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*))::{lambda()#1}::operator()() const /usr/include/c++/12/mutex:788 (gdb+0x320e30) #24 std::once_flag::_Prepare_execution::_Prepare_execution<std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&)::{lambda()#1}>(void (std::__future_base::_State_baseV2::*&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*))::{lambda()#1}::_FUN() /usr/include/c++/12/mutex:788 (gdb+0x320e30) #25 pthread_once ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:1517 (libtsan.so.2+0x46512) #26 __gthread_once /usr/include/x86_64-linux-gnu/c++/12/bits/gthr-default.h:700 (gdb+0x321f9d) #27 void std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&) /usr/include/c++/12/mutex:859 (gdb+0x321f9d) #28 std::__future_base::_State_baseV2::_M_set_result(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>, bool) /usr/include/c++/12/future:412 (gdb+0x9dfab4) #29 std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run() /usr/include/c++/12/future:1472 (gdb+0x9dfab4) #30 std::packaged_task<void ()>::operator()() /usr/include/c++/12/future:1605 (gdb+0x9dfab4) #31 gdb::thread_pool::thread_function() ../../binutils-gdb/gdbsupport/thread-pool.cc:245 (gdb+0x9dfab4) #32 void std::__invoke_impl<void, void (gdb::thread_pool::*)(), gdb::thread_pool*>(std::__invoke_memfun_deref, void (gdb::thread_pool::*&&)(), gdb::thread_pool*&&) /usr/include/c++/12/bits/invoke.h:74 (gdb+0x9e0cc3) #33 std::__invoke_result<void (gdb::thread_pool::*)(), gdb::thread_pool*>::type std::__invoke<void (gdb::thread_pool::*)(), gdb::thread_pool*>(void (gdb::thread_pool::*&&)(), gdb::thread_pool*&&) /usr/include/c++/12/bits/invoke.h:96 (gdb+0x9e0cc3) #34 void std::thread::_Invoker<std::tuple<void (gdb::thread_pool::*)(), gdb::thread_pool*> >::_M_invoke<0ul, 1ul>(std::_Index_tuple<0ul, 1ul>) /usr/include/c++/12/bits/std_thread.h:252 (gdb+0x9e0cc3) #35 std::thread::_Invoker<std::tuple<void (gdb::thread_pool::*)(), gdb::thread_pool*> >::operator()() /usr/include/c++/12/bits/std_thread.h:259 (gdb+0x9e0cc3) #36 std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (gdb::thread_pool::*)(), gdb::thread_pool*> > >::_M_run() /usr/include/c++/12/bits/std_thread.h:210 (gdb+0x9e0cc3) #37 execute_native_thread_routine <null> (gdb+0xa90592) Location is heap block of size 4064 at 0x7b8000020000 allocated by thread T2: #0 malloc ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:647 (libtsan.so.2+0x3ebb8) #1 xmalloc ../../binutils-gdb/gdb/alloc.c:52 (gdb+0x18f026) #2 call_chunkfun ../../binutils-gdb/libiberty/obstack.c:94 (gdb+0x9a5ae4) #3 _obstack_begin_worker ../../binutils-gdb/libiberty/obstack.c:141 (gdb+0x9a5ae4) #4 _obstack_begin ../../binutils-gdb/libiberty/obstack.c:164 (gdb+0x9a5b69) #5 auto_obstack::auto_obstack() ../../binutils-gdb/gdb/../gdbsupport/gdb_obstack.h:123 (gdb+0x380913) #6 cooked_index_shard::cooked_index_shard() ../../binutils-gdb/gdb/dwarf2/cooked-index.h:270 (gdb+0x380913) #7 cooked_index_storage::cooked_index_storage() ../../binutils-gdb/gdb/dwarf2/read.c:4411 (gdb+0x380913) #8 cooked_index_debug_info::process_cus(unsigned long, __gnu_cxx::__normal_iterator<std::unique_ptr<dwarf2_per_cu_data, dwarf2_per_cu_data_deleter>*, std::vector<std::unique_ptr<dwarf2_per_cu_data, dwarf2_per_cu_data_deleter>, std::allocator<std::unique_ptr<dwarf2_per_cu_data, dwarf2_per_cu_data_deleter> > > >, __gnu_cxx::__normal_iterator<std::unique_ptr<dwarf2_per_cu_data, dwarf2_per_cu_data_deleter>*, std::vector<std::unique_ptr<dwarf2_per_cu_data, dwarf2_per_cu_data_deleter>, std::allocator<std::unique_ptr<dwarf2_per_cu_data, dwarf2_per_cu_data_deleter> > > >) ../../binutils-gdb/gdb/dwarf2/read.c:4926 (gdb+0x39c672) #9 operator() ../../binutils-gdb/gdb/dwarf2/read.c:5035 (gdb+0x39dcb5) #10 __invoke_impl<void, cooked_index_debug_info::do_reading()::<lambda()>&> /usr/include/c++/12/bits/invoke.h:61 (gdb+0x39dcb5) #11 __invoke_r<void, cooked_index_debug_info::do_reading()::<lambda()>&> /usr/include/c++/12/bits/invoke.h:111 (gdb+0x39dcb5) #12 _M_invoke /usr/include/c++/12/bits/std_function.h:290 (gdb+0x39dcb5) #13 std::function<void ()>::operator()() const /usr/include/c++/12/bits/std_function.h:591 (gdb+0x9d88f5) #14 operator() ../../binutils-gdb/gdbsupport/task-group.cc:68 (gdb+0x9d88f5) #15 __invoke_impl<void, gdb::task_group::impl::start()::<lambda()>&> /usr/include/c++/12/bits/invoke.h:61 (gdb+0x9d88f5) #16 __invoke_r<void, gdb::task_group::impl::start()::<lambda()>&> /usr/include/c++/12/bits/invoke.h:111 (gdb+0x9d88f5) #17 _M_invoke /usr/include/c++/12/bits/std_function.h:290 (gdb+0x9d88f5) #18 std::function<void ()>::operator()() const /usr/include/c++/12/bits/std_function.h:591 (gdb+0x321099) #19 void std::__invoke_impl<void, std::function<void ()>&>(std::__invoke_other, std::function<void ()>&) /usr/include/c++/12/bits/invoke.h:61 (gdb+0x321099) #20 std::enable_if<is_invocable_r_v<void, std::function<void ()>&>, void>::type std::__invoke_r<void, std::function<void ()>&>(std::function<void ()>&) /usr/include/c++/12/bits/invoke.h:111 (gdb+0x321099) #21 std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run()::{lambda()#1}::operator()() const /usr/include/c++/12/future:1469 (gdb+0x321099) #22 std::__future_base::_Task_setter<std::unique_ptr<std::__future_base::_Result<void>, std::__future_base::_Result_base::_Deleter>, std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run()::{lambda()#1}, void>::operator()() const /usr/include/c++/12/future:1410 (gdb+0x321099) #23 std::unique_ptr<std::__future_base::_Result<void>, std::__future_base::_Result_base::_Deleter> std::__invoke_impl<std::unique_ptr<std::__future_base::_Result<void>, std::__future_base::_Result_base::_Deleter>, std::__future_base::_Task_setter<std::unique_ptr<std::__future_base::_Result<void>, std::__future_base::_Result_base::_Deleter>, std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run()::{lambda()#1}, void>&>(std::__invoke_other, std::__future_base::_Task_setter<std::unique_ptr<std::__future_base::_Result<void>, std::__future_base::_Result_base::_Deleter>, std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run()::{lambda()#1}, void>&) /usr/include/c++/12/bits/invoke.h:61 (gdb+0x321099) #24 std::enable_if<is_invocable_r_v<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter>, std::__future_base::_Task_setter<std::unique_ptr<std::__future_base::_Result<void>, std::__future_base::_Result_base::_Deleter>, std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run()::{lambda()#1}, void>&>, std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> >::type std::__invoke_r<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter>, std::__future_base::_Task_setter<std::unique_ptr<std::__future_base::_Result<void>, std::__future_base::_Result_base::_Deleter>, std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run()::{lambda()#1}, void>&>(std::__future_base::_Task_setter<std::unique_ptr<std::__future_base::_Result<void>, std::__future_base::_Result_base::_Deleter>, std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run()::{lambda()#1}, void>&) /usr/include/c++/12/bits/invoke.h:116 (gdb+0x321099) #25 std::_Function_handler<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> (), std::__future_base::_Task_setter<std::unique_ptr<std::__future_base::_Result<void>, std::__future_base::_Result_base::_Deleter>, std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run()::{lambda()#1}, void> >::_M_invoke(std::_Any_data const&) /usr/include/c++/12/bits/std_function.h:291 (gdb+0x321099) #26 std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>::operator()() const /usr/include/c++/12/bits/std_function.h:591 (gdb+0x3214c9) #27 std::__future_base::_State_baseV2::_M_do_set(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*) /usr/include/c++/12/future:572 (gdb+0x3214c9) #28 void std::__invoke_impl<void, void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::__invoke_memfun_deref, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&) /usr/include/c++/12/bits/invoke.h:74 (gdb+0x320e30) #29 std::__invoke_result<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>::type std::__invoke<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&) /usr/include/c++/12/bits/invoke.h:96 (gdb+0x320e30) #30 std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&)::{lambda()#1}::operator()() const /usr/include/c++/12/mutex:852 (gdb+0x320e30) #31 std::once_flag::_Prepare_execution::_Prepare_execution<std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&)::{lambda()#1}>(void (std::__future_base::_State_baseV2::*&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*))::{lambda()#1}::operator()() const /usr/include/c++/12/mutex:788 (gdb+0x320e30) #32 std::once_flag::_Prepare_execution::_Prepare_execution<std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&)::{lambda()#1}>(void (std::__future_base::_State_baseV2::*&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*))::{lambda()#1}::_FUN() /usr/include/c++/12/mutex:788 (gdb+0x320e30) #33 pthread_once ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:1517 (libtsan.so.2+0x46512) #34 __gthread_once /usr/include/x86_64-linux-gnu/c++/12/bits/gthr-default.h:700 (gdb+0x321f9d) #35 void std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&) /usr/include/c++/12/mutex:859 (gdb+0x321f9d) #36 std::__future_base::_State_baseV2::_M_set_result(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>, bool) /usr/include/c++/12/future:412 (gdb+0x9dfab4) #37 std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run() /usr/include/c++/12/future:1472 (gdb+0x9dfab4) #38 std::packaged_task<void ()>::operator()() /usr/include/c++/12/future:1605 (gdb+0x9dfab4) #39 gdb::thread_pool::thread_function() ../../binutils-gdb/gdbsupport/thread-pool.cc:245 (gdb+0x9dfab4) #40 void std::__invoke_impl<void, void (gdb::thread_pool::*)(), gdb::thread_pool*>(std::__invoke_memfun_deref, void (gdb::thread_pool::*&&)(), gdb::thread_pool*&&) /usr/include/c++/12/bits/invoke.h:74 (gdb+0x9e0cc3) #41 std::__invoke_result<void (gdb::thread_pool::*)(), gdb::thread_pool*>::type std::__invoke<void (gdb::thread_pool::*)(), gdb::thread_pool*>(void (gdb::thread_pool::*&&)(), gdb::thread_pool*&&) /usr/include/c++/12/bits/invoke.h:96 (gdb+0x9e0cc3) #42 void std::thread::_Invoker<std::tuple<void (gdb::thread_pool::*)(), gdb::thread_pool*> >::_M_invoke<0ul, 1ul>(std::_Index_tuple<0ul, 1ul>) /usr/include/c++/12/bits/std_thread.h:252 (gdb+0x9e0cc3) #43 std::thread::_Invoker<std::tuple<void (gdb::thread_pool::*)(), gdb::thread_pool*> >::operator()() /usr/include/c++/12/bits/std_thread.h:259 (gdb+0x9e0cc3) #44 std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (gdb::thread_pool::*)(), gdb::thread_pool*> > >::_M_run() /usr/include/c++/12/bits/std_thread.h:210 (gdb+0x9e0cc3) #45 execute_native_thread_routine <null> (gdb+0xa90592) Thread T4 'gdb worker' (tid=29556, running) created by main thread at: #0 pthread_create ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:1001 (libtsan.so.2+0x5e686) #1 std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)()) <null> (gdb+0xa90668) #2 update_thread_pool_size() ../../binutils-gdb/gdb/maint.c:865 (gdb+0x53356b) #3 captured_main_1 ../../binutils-gdb/gdb/main.c:1054 (gdb+0x529a13) #4 captured_main ../../binutils-gdb/gdb/main.c:1328 (gdb+0x52b06a) #5 gdb_main(captured_main_args*) ../../binutils-gdb/gdb/main.c:1357 (gdb+0x52b06a) #6 main ../../binutils-gdb/gdb/gdb.c:38 (gdb+0x1162e2) Thread T2 'gdb worker' (tid=29554, running) created by main thread at: #0 pthread_create ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:1001 (libtsan.so.2+0x5e686) #1 std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)()) <null> (gdb+0xa90668) #2 update_thread_pool_size() ../../binutils-gdb/gdb/maint.c:865 (gdb+0x53356b) #3 captured_main_1 ../../binutils-gdb/gdb/main.c:1054 (gdb+0x529a13) #4 captured_main ../../binutils-gdb/gdb/main.c:1328 (gdb+0x52b06a) #5 gdb_main(captured_main_args*) ../../binutils-gdb/gdb/main.c:1357 (gdb+0x52b06a) #6 main ../../binutils-gdb/gdb/gdb.c:38 (gdb+0x1162e2) SUMMARY: ThreadSanitizer: data race ../../binutils-gdb/gdb/dwarf2/cooked-index.c:220 in cooked_index_entry::full_name(obstack*, bool) const ================== (gdb) FAIL: gdb.base/annota1.exp: set height 0 break annota1.c:15 Breakpoint 1 at 0x115b: file /home/ed/gnu/gdb-build-y/gdb/testsuite/../../../binutils-gdb/gdb/testsuite/gdb.base/annota1.c, line 15. (gdb) PASS: gdb.base/annota1.exp: breakpoint main set annotate 2
Hmm... Read of size 8 at 0x7b8000020288 by main thread: #0 cooked_index_entry::full_name(obstack*, bool) const ../../binutils-gdb/gdb/dwarf2/cooked-index.c:220 (gdb+0x31c114) When I disassemble the code in question it looks like a mis-compilation. 31c0fc: e8 3f 57 db ff call d1840 <__tsan_func_entry@plt> 31c101: 48 89 df mov %rbx,%rdi 31c104: e8 37 5c db ff call d1d40 <__tsan_read8@plt> 31c109: 48 8d 7b 08 lea 0x8(%rbx),%rdi 31c10d: 4c 8b 23 mov (%rbx),%r12 31c110: e8 2b 5c db ff call d1d40 <__tsan_read8@plt> 31c115: 48 8d 7b 14 lea 0x14(%rbx),%rdi 31c119: 45 84 ed test %r13b,%r13b 31c11c: 4c 0f 44 63 08 cmove 0x8(%rbx),%r12 31c121: e8 aa 5e db ff call d1fd0 <__tsan_read1@plt> 31c126: 0f b6 43 14 movzbl 0x14(%rbx),%eax 31c12a: a8 04 test $0x4,%al 31c12c: 74 1a je 31c148 <_ZNK18cooked_index_entry9full_nameEP7obstackb+0x68> 31c12e: e8 fd 61 db ff call d2330 <__tsan_func_exit@plt> So this->name is read unconditinally, and the read value is replaced with this->canonical conditionally with a cmove, that is actually not executed, but from the tsan instrumentation it looks as if the read is done in any case. instead of the used gcc version 12.2.0 (Debian 12.2.0-14) I can also bootstrap a brand new gcc and see what happens there, although I would still suggest to rewrite the code in question like this: const char **local_name = for_main ? &name : &canonical; if ((flags & IS_LINKAGE) != 0 || get_parent () == nullptr) return *local_name;
(In reply to Bernd Edlinger from comment #9) > So this->name is read unconditinally, and the read value > is replaced with this->canonical conditionally with a cmove, > that is actually not executed, but from the tsan instrumentation > it looks as if the read is done in any case. Reminds me of https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110799
(In reply to Tom de Vries from comment #10) > (In reply to Bernd Edlinger from comment #9) > > So this->name is read unconditinally, and the read value > > is replaced with this->canonical conditionally with a cmove, > > that is actually not executed, but from the tsan instrumentation > > it looks as if the read is done in any case. > > Reminds me of https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110799 Yeah that explains really a lot. Now with this little tweak the number of warnings drops to zero: diff --git a/gdb/dwarf2/cooked-index.c b/gdb/dwarf2/cooked-index.c index 4073c924890..10f2b697a4c 100644 --- a/gdb/dwarf2/cooked-index.c +++ b/gdb/dwarf2/cooked-index.c @@ -217,7 +217,7 @@ cooked_index_entry::matches (domain_search_flags kind) const const char * cooked_index_entry::full_name (struct obstack *storage, bool for_main) const { - const char *local_name = for_main ? name : canonical; + const char *const &local_name = for_main ? name : canonical; if ((flags & IS_LINKAGE) != 0 || get_parent () == nullptr) return local_name; Would you like to include this into your patch? Thanks Bernd.
(In reply to Bernd Edlinger from comment #11) > Now with this little tweak the number of warnings drops to zero: > > diff --git a/gdb/dwarf2/cooked-index.c b/gdb/dwarf2/cooked-index.c > index 4073c924890..10f2b697a4c 100644 > --- a/gdb/dwarf2/cooked-index.c > +++ b/gdb/dwarf2/cooked-index.c > @@ -217,7 +217,7 @@ cooked_index_entry::matches (domain_search_flags kind) > const > const char * > cooked_index_entry::full_name (struct obstack *storage, bool for_main) const > { > - const char *local_name = for_main ? name : canonical; > + const char *const &local_name = for_main ? name : canonical; > > if ((flags & IS_LINKAGE) != 0 || get_parent () == nullptr) > return local_name; > > I think I prefer a workaround like this: ... +#if defined (__SANITIZE_THREAD__) && defined (__GNUC__) && !defined (__clang__) +/* Work around PR gcc/110799. */ +__attribute__((optimize("-fno-hoist-adjacent-loads"))) +#endif ... which doesn't require any changes in the function body.
(In reply to Tom de Vries from comment #12) > (In reply to Bernd Edlinger from comment #11) > > Now with this little tweak the number of warnings drops to zero: > > > > diff --git a/gdb/dwarf2/cooked-index.c b/gdb/dwarf2/cooked-index.c > > index 4073c924890..10f2b697a4c 100644 > > --- a/gdb/dwarf2/cooked-index.c > > +++ b/gdb/dwarf2/cooked-index.c > > @@ -217,7 +217,7 @@ cooked_index_entry::matches (domain_search_flags kind) > > const > > const char * > > cooked_index_entry::full_name (struct obstack *storage, bool for_main) const > > { > > - const char *local_name = for_main ? name : canonical; > > + const char *const &local_name = for_main ? name : canonical; > > > > if ((flags & IS_LINKAGE) != 0 || get_parent () == nullptr) > > return local_name; > > > > > > I think I prefer a workaround like this: > ... > +#if defined (__SANITIZE_THREAD__) && defined (__GNUC__) && !defined > (__clang__) > > +/* Work around PR gcc/110799. */ > +__attribute__((optimize("-fno-hoist-adjacent-loads"))) > +#endif > ... > which doesn't require any changes in the function body. That's also okay for me, if you prefer that one. Maybe you can just add "&& __GNUC__ < 14" to the if-condition since the mis-compilation is fixed with gcc-14, while the all gcc-13 versions seem to be affected. I've just tried that out.
(In reply to Tom de Vries from comment #12) > I think I prefer a workaround like this: > ... > +#if defined (__SANITIZE_THREAD__) && defined (__GNUC__) && !defined > (__clang__) > > +/* Work around PR gcc/110799. */ > +__attribute__((optimize("-fno-hoist-adjacent-loads"))) > +#endif > ... > which doesn't require any changes in the function body. Should we just require TSAN builds to always use this option? Or would that obscure real bugs sometimes?
(In reply to Tom Tromey from comment #14) > (In reply to Tom de Vries from comment #12) > > > I think I prefer a workaround like this: > > ... > > +#if defined (__SANITIZE_THREAD__) && defined (__GNUC__) && !defined > > (__clang__) > > > > +/* Work around PR gcc/110799. */ > > +__attribute__((optimize("-fno-hoist-adjacent-loads"))) > > +#endif > > ... > > which doesn't require any changes in the function body. > > Should we just require TSAN builds to always use this option? That was my initial idea: in gdb/Makefile.in, do something like: ... ifneq ($(filter -fsanitizer=thread,$(CFLAGS) $(CXXFLAGS)),) CFLAGS = $(CFLAGS) -fno-hoist-adjacent-loads CXXFLAGS = $(CXXFLAGS) -fno-hoist-adjacent-loads endif ... but clang doesn't support this option. So, we could export gcc-ness of the compiler to the makefile level. Or, use -O0 instead of -fno-hoist-adjacent-loads which I guess should be accepted by all compilers using -fsanitizer=thread. But that wouldn't work if sufficient amount of -f flags would be provided to enable options, so it's not watertight. Either way, there's the question of scope. We'd do this also in gdbserver and gdbsupport, but what about say bfd, readline, libopcodes? Should this be at the top-level? In that case, it needs to be proposed for the gcc repository. I figured a local fix using __SANITIZE_THREAD__ doesn't require any infrastructure changes, so propose that first. If that's not acceptable, we can try to export gcc-ness to the makefile. > Or would that obscure real bugs sometimes? I don't think so.
I was actually thinking of something a lot less automated: just a note somewhere saying "if you want TSAN you also need this option". However something more robust is probably better I guess. Can we just add your code snippet to common-defs.h?
(In reply to Tom Tromey from comment #16) > I was actually thinking of something a lot less automated: just > a note somewhere saying "if you want TSAN you also need this option". > > However something more robust is probably better I guess. > Can we just add your code snippet to common-defs.h? Aha, so like this: ... diff --git a/gdbsupport/common-defs.h b/gdbsupport/common-defs.h index 6120719480b..60574dcd369 100644 --- a/gdbsupport/common-defs.h +++ b/gdbsupport/common-defs.h @@ -20,6 +20,13 @@ #ifndef COMMON_COMMON_DEFS_H #define COMMON_COMMON_DEFS_H +#if defined (__SANITIZE_THREAD__) && defined (__GNUC__) \ + && !defined (__clang__) && __GNUC__ <= 13 + +/* Work around PR gcc/110799. */ +#pragma gcc optimize("-fno-hoist-adjacent-loads") +#endif + #include <gdbsupport/config.h> #undef PACKAGE_NAME ... That would work.
(In reply to Tom de Vries from comment #17) > (In reply to Tom Tromey from comment #16) > > I was actually thinking of something a lot less automated: just > > a note somewhere saying "if you want TSAN you also need this option". > > > > However something more robust is probably better I guess. > > Can we just add your code snippet to common-defs.h? > > Aha, so like this: > ... > diff --git a/gdbsupport/common-defs.h b/gdbsupport/common-defs.h > index 6120719480b..60574dcd369 100644 > --- a/gdbsupport/common-defs.h > +++ b/gdbsupport/common-defs.h > @@ -20,6 +20,13 @@ > #ifndef COMMON_COMMON_DEFS_H > #define COMMON_COMMON_DEFS_H > > +#if defined (__SANITIZE_THREAD__) && defined (__GNUC__) \ > + && !defined (__clang__) && __GNUC__ <= 13 > + > +/* Work around PR gcc/110799. */ > +#pragma gcc optimize("-fno-hoist-adjacent-loads") > +#endif > + > #include <gdbsupport/config.h> > > #undef PACKAGE_NAME > ... > > That would work. Bernd, can you test if this fixes your problem? I'm having trouble reproducing.
(In reply to Tom de Vries from comment #18) > (In reply to Tom de Vries from comment #17) > > (In reply to Tom Tromey from comment #16) > > > I was actually thinking of something a lot less automated: just > > > a note somewhere saying "if you want TSAN you also need this option". > > > > > > However something more robust is probably better I guess. > > > Can we just add your code snippet to common-defs.h? > > > > Aha, so like this: > > ... > > diff --git a/gdbsupport/common-defs.h b/gdbsupport/common-defs.h > > index 6120719480b..60574dcd369 100644 > > --- a/gdbsupport/common-defs.h > > +++ b/gdbsupport/common-defs.h > > @@ -20,6 +20,13 @@ > > #ifndef COMMON_COMMON_DEFS_H > > #define COMMON_COMMON_DEFS_H > > > > +#if defined (__SANITIZE_THREAD__) && defined (__GNUC__) \ > > + && !defined (__clang__) && __GNUC__ <= 13 > > + > > +/* Work around PR gcc/110799. */ > > +#pragma gcc optimize("-fno-hoist-adjacent-loads") > > +#endif > > + > > #include <gdbsupport/config.h> > > > > #undef PACKAGE_NAME > > ... > > > > That would work. > > Bernd, can you test if this fixes your problem? I'm having trouble > reproducing. I've managed to reproduce it now. Currently testing. FWIW, the pragma line should be: ... -#pragma gcc optimize("-fno-hoist-adjacent-loads") +#pragma GCC optimize("-fno-hoist-adjacent-loads") ...
Hi Tom, really good work, my testing is also OK.
https://sourceware.org/pipermail/gdb-patches/2024-October/212381.html
The master branch has been updated by Tom de Vries <vries@sourceware.org>: https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=9a56fae565b641d6e7557e8c59adf9018d304041 commit 9a56fae565b641d6e7557e8c59adf9018d304041 Author: Tom de Vries <tdevries@suse.de> Date: Fri Oct 18 00:18:24 2024 +0200 [gdb/build] Use -fno-hoist-adjacent-loads for gcc <= 13 When building gdb with gcc 12 and -fsanitize=threads while renabling background dwarf reading by setting dwarf_synchronous to false, I run into: ... (gdb) file amd64-watchpoint-downgrade Reading symbols from amd64-watchpoint-downgrade... (gdb) watch global_var ================== WARNING: ThreadSanitizer: data race (pid=20124) Read of size 8 at 0x7b80000500d8 by main thread: #0 cooked_index_entry::full_name(obstack*, bool) const cooked-index.c:220 #1 cooked_index::get_main_name(obstack*, language*) const cooked-index.c:735 #2 cooked_index_worker::wait(cooked_state, bool) cooked-index.c:559 #3 cooked_index::wait(cooked_state, bool) cooked-index.c:631 #4 cooked_index_functions::wait(objfile*, bool) cooked-index.h:729 #5 cooked_index_functions::compute_main_name(objfile*) cooked-index.h:806 #6 objfile::compute_main_name() symfile-debug.c:461 #7 find_main_name symtab.c:6503 #8 main_language() symtab.c:6608 #9 set_initial_language_callback symfile.c:1634 #10 get_current_language() language.c:96 ... Previous write of size 8 at 0x7b80000500d8 by thread T1: #0 cooked_index_shard::finalize(parent_map_map const*) \ dwarf2/cooked-index.c:409 #1 operator() cooked-index.c:663 ... ... SUMMARY: ThreadSanitizer: data race cooked-index.c:220 in \ cooked_index_entry::full_name(obstack*, bool) const ================== Hardware watchpoint 1: global_var (gdb) PASS: gdb.arch/amd64-watchpoint-downgrade.exp: watch global_var ... This was also reported in PR31715. This is due do gcc PR110799 [1], generating wrong code with -fhoist-adjacent-loads, and causing a false positive for -fsanitize=threads. Work around the gcc PR by forcing -fno-hoist-adjacent-loads for gcc <= 13 and -fsanitize=threads. Tested in that same configuration on x86_64-linux. Remaining ThreadSanitizer problems are the ones reported in PR31626 (gdb.rust/dwindex.exp) and PR32247 (gdb.trace/basic-libipa.exp). PR gdb/31715 Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=31715 Tested-By: Bernd Edlinger <bernd.edlinger@hotmail.de> Approved-By: Tom Tromey <tom@tromey.com> [1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110799
Committed patch with workaround, marking the PR resolved-fixed.