Bug 31262 - [gdb] ThreadSanitizer: data raceindex-cache.c:76 in index_cache::enable()
Summary: [gdb] ThreadSanitizer: data raceindex-cache.c:76 in index_cache::enable()
Status: RESOLVED FIXED
Alias: None
Product: gdb
Classification: Unclassified
Component: gdb (show other bugs)
Version: HEAD
: P2 normal
Target Milestone: 15.1
Assignee: Tom Tromey
URL:
Keywords:
Depends on:
Blocks: 31751
  Show dependency treegraph
 
Reported: 2024-01-18 09:32 UTC by Tom de Vries
Modified: 2024-05-17 14:17 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Tom de Vries 2024-01-18 09:32:26 UTC
When building gdb with O0 fsanitize=thread, and running test-case gdb.base/index-cache.exp, I get:
...
(gdb) PASS: gdb.base/index-cache.exp: test_basic_stuff: index-cache is disabled by default
set index-cache enabled on
==================
[1m[31mWARNING: ThreadSanitizer: data race (pid=565983)
[1m[0m[1m[34m  Write of size 1 at 0x000003280448 by main thread:
[1m[0m    #0 index_cache::enable() /home/vries/gdb/src/gdb/dwarf2/index-cache.c:76 (gdb+0x837634) (BuildId: 6dc308d9bc2da51d7adf979315fabd66fb46e8a3)
    #1 set_index_cache_enabled_command /home/vries/gdb/src/gdb/dwarf2/index-cache.c:294 (gdb+0x838104) (BuildId: 6dc308d9bc2da51d7adf979315fabd66fb46e8a3)
    #2 bool setting::set<bool>(bool const&) /home/vries/gdb/src/gdb/command.h:353 (gdb+0x709c10) (BuildId: 6dc308d9bc2da51d7adf979315fabd66fb46e8a3)
    #3 do_set_command(char const*, int, cmd_list_element*) /home/vries/gdb/src/gdb/cli/cli-setshow.c:414 (gdb+0x708530) (BuildId: 6dc308d9bc2da51d7adf979315fabd66fb46e8a3)
    #4 execute_command(char const*, int) /home/vries/gdb/src/gdb/top.c:567 (gdb+0xff73cc) (BuildId: 6dc308d9bc2da51d7adf979315fabd66fb46e8a3)
    #5 command_handler(char const*) /home/vries/gdb/src/gdb/event-top.c:566 (gdb+0x942488) (BuildId: 6dc308d9bc2da51d7adf979315fabd66fb46e8a3)
    #6 command_line_handler(std::unique_ptr<char, gdb::xfree_deleter<char> >&&) /home/vries/gdb/src/gdb/event-top.c:802 (gdb+0x942bc0) (BuildId: 6dc308d9bc2da51d7adf979315fabd66fb46e8a3)
    #7 tui_command_line_handler /home/vries/gdb/src/gdb/tui/tui-interp.c:104 (gdb+0x10365f8) (BuildId: 6dc308d9bc2da51d7adf979315fabd66fb46e8a3)
    #8 gdb_rl_callback_handler /home/vries/gdb/src/gdb/event-top.c:259 (gdb+0x941884) (BuildId: 6dc308d9bc2da51d7adf979315fabd66fb46e8a3)
    #9 rl_callback_read_char /home/vries/gdb/src/readline/readline/callback.c:290 (gdb+0x11a2c7c) (BuildId: 6dc308d9bc2da51d7adf979315fabd66fb46e8a3)
    #10 gdb_rl_callback_read_char_wrapper_noexcept /home/vries/gdb/src/gdb/event-top.c:195 (gdb+0x9415f8) (BuildId: 6dc308d9bc2da51d7adf979315fabd66fb46e8a3)
    #11 gdb_rl_callback_read_char_wrapper /home/vries/gdb/src/gdb/event-top.c:234 (gdb+0x941720) (BuildId: 6dc308d9bc2da51d7adf979315fabd66fb46e8a3)
    #12 stdin_event_handler /home/vries/gdb/src/gdb/ui.c:155 (gdb+0x1079320) (BuildId: 6dc308d9bc2da51d7adf979315fabd66fb46e8a3)
    #13 handle_file_event /home/vries/gdb/src/gdbsupport/event-loop.cc:573 (gdb+0x1cf5678) (BuildId: 6dc308d9bc2da51d7adf979315fabd66fb46e8a3)
    #14 gdb_wait_for_event /home/vries/gdb/src/gdbsupport/event-loop.cc:694 (gdb+0x1cf5d3c) (BuildId: 6dc308d9bc2da51d7adf979315fabd66fb46e8a3)
    #15 gdb_do_one_event(int) /home/vries/gdb/src/gdbsupport/event-loop.cc:264 (gdb+0x1cf4074) (BuildId: 6dc308d9bc2da51d7adf979315fabd66fb46e8a3)
    #16 start_event_loop /home/vries/gdb/src/gdb/main.c:408 (gdb+0xb79354) (BuildId: 6dc308d9bc2da51d7adf979315fabd66fb46e8a3)
    #17 captured_command_loop /home/vries/gdb/src/gdb/main.c:472 (gdb+0xb79584) (BuildId: 6dc308d9bc2da51d7adf979315fabd66fb46e8a3)
    #18 captured_main /home/vries/gdb/src/gdb/main.c:1342 (gdb+0xb7b99c) (BuildId: 6dc308d9bc2da51d7adf979315fabd66fb46e8a3)
    #19 gdb_main(captured_main_args*) /home/vries/gdb/src/gdb/main.c:1361 (gdb+0xb7ba4c) (BuildId: 6dc308d9bc2da51d7adf979315fabd66fb46e8a3)
    #20 main /home/vries/gdb/src/gdb/gdb.c:39 (gdb+0x423ce8) (BuildId: 6dc308d9bc2da51d7adf979315fabd66fb46e8a3)

[1m[34m  Previous read of size 1 at 0x000003280448 by thread T5:
[1m[0m    #0 index_cache::enabled() const /home/vries/gdb/src/gdb/dwarf2/index-cache.h:70 (gdb+0x8389a4) (BuildId: 6dc308d9bc2da51d7adf979315fabd66fb46e8a3)
    #1 index_cache_store_context::index_cache_store_context(index_cache const&, dwarf2_per_bfd*) /home/vries/gdb/src/gdb/dwarf2/index-cache.c:93 (gdb+0x837730) (BuildId: 6dc308d9bc2da51d7adf979315fabd66fb46e8a3)
    #2 cooked_index::set_contents(std::vector<std::unique_ptr<cooked_index_shard, std::default_delete<cooked_index_shard> >, std::allocator<std::unique_ptr<cooked_index_shard, std::default_delete<cooked_index_shard> > > >&&) /home/vries/gdb/src/gdb/dwarf2/cooked-index.c:489 (gdb+0x7f6fec) (BuildId: 6dc308d9bc2da51d7adf979315fabd66fb46e8a3)
    #3 cooked_index_worker::done_reading() /home/vries/gdb/src/gdb/dwarf2/read.c:4901 (gdb+0x89e980) (BuildId: 6dc308d9bc2da51d7adf979315fabd66fb46e8a3)
    #4 operator() /home/vries/gdb/src/gdb/dwarf2/read.c:4960 (gdb+0x89eb40) (BuildId: 6dc308d9bc2da51d7adf979315fabd66fb46e8a3)
    #5 __invoke_impl<void, cooked_index_worker::do_reading()::<lambda()>&> /usr/include/c++/13/bits/invoke.h:61 (gdb+0x8decb4) (BuildId: 6dc308d9bc2da51d7adf979315fabd66fb46e8a3)
    #6 __invoke_r<void, cooked_index_worker::do_reading()::<lambda()>&> /usr/include/c++/13/bits/invoke.h:111 (gdb+0x8dddec) (BuildId: 6dc308d9bc2da51d7adf979315fabd66fb46e8a3)
    #7 _M_invoke /usr/include/c++/13/bits/std_function.h:290 (gdb+0x8db118) (BuildId: 6dc308d9bc2da51d7adf979315fabd66fb46e8a3)
    #8 std::function<void ()>::operator()() const /usr/include/c++/13/bits/std_function.h:591 (gdb+0x70c308) (BuildId: 6dc308d9bc2da51d7adf979315fabd66fb46e8a3)
    #9 gdb::task_group::impl::~impl() /home/vries/gdb/src/gdbsupport/task-group.cc:39 (gdb+0x1d03610) (BuildId: 6dc308d9bc2da51d7adf979315fabd66fb46e8a3)
    #10 std::_Sp_counted_ptr<gdb::task_group::impl*, (__gnu_cxx::_Lock_policy)2>::_M_dispose() /usr/include/c++/13/bits/shared_ptr_base.h:428 (gdb+0x1d04690) (BuildId: 6dc308d9bc2da51d7adf979315fabd66fb46e8a3)
    #11 std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release_last_use() /usr/include/c++/13/bits/shared_ptr_base.h:175 (gdb+0x63bf20) (BuildId: 6dc308d9bc2da51d7adf979315fabd66fb46e8a3)
    #12 std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release() /usr/include/c++/13/bits/shared_ptr_base.h:361 (gdb+0x637758) (BuildId: 6dc308d9bc2da51d7adf979315fabd66fb46e8a3)
    #13 std::__shared_count<(__gnu_cxx::_Lock_policy)2>::~__shared_count() /usr/include/c++/13/bits/shared_ptr_base.h:1071 (gdb+0x63c0b8) (BuildId: 6dc308d9bc2da51d7adf979315fabd66fb46e8a3)
    #14 std::__shared_ptr<gdb::task_group::impl, (__gnu_cxx::_Lock_policy)2>::~__shared_ptr() /usr/include/c++/13/bits/shared_ptr_base.h:1524 (gdb+0x7fc9e8) (BuildId: 6dc308d9bc2da51d7adf979315fabd66fb46e8a3)
    #15 std::shared_ptr<gdb::task_group::impl>::~shared_ptr() /usr/include/c++/13/bits/shared_ptr.h:175 (gdb+0x7fca20) (BuildId: 6dc308d9bc2da51d7adf979315fabd66fb46e8a3)
    #16 ~<lambda> /home/vries/gdb/src/gdbsupport/task-group.cc:66 (gdb+0x1d026cc) (BuildId: 6dc308d9bc2da51d7adf979315fabd66fb46e8a3)
    #17 _M_destroy /usr/include/c++/13/bits/std_function.h:175 (gdb+0x1d03228) (BuildId: 6dc308d9bc2da51d7adf979315fabd66fb46e8a3)
    #18 _M_manager /usr/include/c++/13/bits/std_function.h:203 (gdb+0x1d0308c) (BuildId: 6dc308d9bc2da51d7adf979315fabd66fb46e8a3)
    #19 _M_manager /usr/include/c++/13/bits/std_function.h:282 (gdb+0x1d02d5c) (BuildId: 6dc308d9bc2da51d7adf979315fabd66fb46e8a3)
    #20 std::_Function_base::~_Function_base() /usr/include/c++/13/bits/std_function.h:244 (gdb+0x431da4) (BuildId: 6dc308d9bc2da51d7adf979315fabd66fb46e8a3)
    #21 std::function<void ()>::~function() /usr/include/c++/13/bits/std_function.h:334 (gdb+0x432cac) (BuildId: 6dc308d9bc2da51d7adf979315fabd66fb46e8a3)
    #22 std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_Impl::~_Impl() /usr/include/c++/13/future:1511 (gdb+0x80f73c) (BuildId: 6dc308d9bc2da51d7adf979315fabd66fb46e8a3)
    #23 std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::~_Task_state() /usr/include/c++/13/future:1477 (gdb+0x810494) (BuildId: 6dc308d9bc2da51d7adf979315fabd66fb46e8a3)
    #24 void std::__new_allocator<int>::destroy<std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()> >(std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>*) /usr/include/c++/13/bits/new_allocator.h:198 (gdb+0x81062c) (BuildId: 6dc308d9bc2da51d7adf979315fabd66fb46e8a3)
    #25 void std::allocator_traits<std::allocator<int> >::destroy<std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()> >(std::allocator<int>&, std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>*) /usr/include/c++/13/bits/alloc_traits.h:558 (gdb+0x81062c)
    #26 std::_Sp_counted_ptr_inplace<std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>, std::allocator<int>, (__gnu_cxx::_Lock_policy)2>::_M_dispose() /usr/include/c++/13/bits/shared_ptr_base.h:613 (gdb+0x81062c)
    #27 std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release_last_use() /usr/include/c++/13/bits/shared_ptr_base.h:175 (gdb+0x63bf20) (BuildId: 6dc308d9bc2da51d7adf979315fabd66fb46e8a3)
    #28 std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release() /usr/include/c++/13/bits/shared_ptr_base.h:361 (gdb+0x637758) (BuildId: 6dc308d9bc2da51d7adf979315fabd66fb46e8a3)
    #29 std::__shared_count<(__gnu_cxx::_Lock_policy)2>::~__shared_count() /usr/include/c++/13/bits/shared_ptr_base.h:1071 (gdb+0x63c0b8) (BuildId: 6dc308d9bc2da51d7adf979315fabd66fb46e8a3)
    #30 std::__shared_ptr<std::__future_base::_Task_state_base<void ()>, (__gnu_cxx::_Lock_policy)2>::~__shared_ptr() /usr/include/c++/13/bits/shared_ptr_base.h:1524 (gdb+0x8ebfd0) (BuildId: 6dc308d9bc2da51d7adf979315fabd66fb46e8a3)
    #31 std::shared_ptr<std::__future_base::_Task_state_base<void ()> >::~shared_ptr() /usr/include/c++/13/bits/shared_ptr.h:175 (gdb+0x8ec008) (BuildId: 6dc308d9bc2da51d7adf979315fabd66fb46e8a3)
    #32 std::packaged_task<void ()>::~packaged_task() /usr/include/c++/13/future:1594 (gdb+0x8ec16c) (BuildId: 6dc308d9bc2da51d7adf979315fabd66fb46e8a3)
    #33 std::_Optional_payload_base<std::packaged_task<void ()> >::_M_destroy() /usr/include/c++/13/optional:287 (gdb+0x1d10c94) (BuildId: 6dc308d9bc2da51d7adf979315fabd66fb46e8a3)
    #34 std::_Optional_payload_base<std::packaged_task<void ()> >::_M_reset() /usr/include/c++/13/optional:318 (gdb+0x1d0fe18) (BuildId: 6dc308d9bc2da51d7adf979315fabd66fb46e8a3)
    #35 std::_Optional_payload<std::packaged_task<void ()>, false, false, false>::~_Optional_payload() /usr/include/c++/13/optional:439 (gdb+0x1d0f500) (BuildId: 6dc308d9bc2da51d7adf979315fabd66fb46e8a3)
    #36 std::_Optional_base<std::packaged_task<void ()>, false, false>::~_Optional_base() /usr/include/c++/13/optional:510 (gdb+0x1d0ed88) (BuildId: 6dc308d9bc2da51d7adf979315fabd66fb46e8a3)
    #37 std::optional<std::packaged_task<void ()> >::~optional() /usr/include/c++/13/optional:705 (gdb+0x1d0ee0c) (BuildId: 6dc308d9bc2da51d7adf979315fabd66fb46e8a3)
    #38 gdb::thread_pool::thread_function() /home/vries/gdb/src/gdbsupport/thread-pool.cc:247 (gdb+0x1d0e82c) (BuildId: 6dc308d9bc2da51d7adf979315fabd66fb46e8a3)
    #39 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++/13/bits/invoke.h:74 (gdb+0x1d12968) (BuildId: 6dc308d9bc2da51d7adf979315fabd66fb46e8a3)
    #40 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++/13/bits/invoke.h:96 (gdb+0x1d12804) (BuildId: 6dc308d9bc2da51d7adf979315fabd66fb46e8a3)
    #41 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++/13/bits/std_thread.h:292 (gdb+0x1d126e4) (BuildId: 6dc308d9bc2da51d7adf979315fabd66fb46e8a3)
    #42 std::thread::_Invoker<std::tuple<void (gdb::thread_pool::*)(), gdb::thread_pool*> >::operator()() /usr/include/c++/13/bits/std_thread.h:299 (gdb+0x1d1266c) (BuildId: 6dc308d9bc2da51d7adf979315fabd66fb46e8a3)
    #43 std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (gdb::thread_pool::*)(), gdb::thread_pool*> > >::_M_run() /usr/include/c++/13/bits/std_thread.h:244 (gdb+0x1d12618) (BuildId: 6dc308d9bc2da51d7adf979315fabd66fb46e8a3)
    #44 execute_native_thread_routine <null> (libstdc++.so.6+0xdda9c) (BuildId: 93e3778007c3847dd08373eb42577dc85c8750e4)

[1m[32m  Location is global 'global_index_cache' of size 48 at 0x000003280428 (gdb+0x3280448)

[1m[0m[1m[36m  Thread T5 'gdb worker' (tid=565994, running) created by main thread at:
[1m[0m    #0 pthread_create <null> (libtsan.so.2+0x4605c) (BuildId: fe872cc4563474b7ad67d63a019aa94e1e0df888)
    #1 std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)()) <null> (libstdc++.so.6+0xddbe4) (BuildId: 93e3778007c3847dd08373eb42577dc85c8750e4)
    #2 gdb::thread_pool::set_thread_count(unsigned long) /home/vries/gdb/src/gdbsupport/thread-pool.cc:169 (gdb+0x1d0e4b4) (BuildId: 6dc308d9bc2da51d7adf979315fabd66fb46e8a3)
    #3 update_thread_pool_size() /home/vries/gdb/src/gdb/maint.c:866 (gdb+0xb87c70) (BuildId: 6dc308d9bc2da51d7adf979315fabd66fb46e8a3)
    #4 captured_main_1 /home/vries/gdb/src/gdb/main.c:1062 (gdb+0xb7a8a4) (BuildId: 6dc308d9bc2da51d7adf979315fabd66fb46e8a3)
    #5 captured_main /home/vries/gdb/src/gdb/main.c:1332 (gdb+0xb7b998) (BuildId: 6dc308d9bc2da51d7adf979315fabd66fb46e8a3)
    #6 gdb_main(captured_main_args*) /home/vries/gdb/src/gdb/main.c:1361 (gdb+0xb7ba4c) (BuildId: 6dc308d9bc2da51d7adf979315fabd66fb46e8a3)
    #7 main /home/vries/gdb/src/gdb/gdb.c:39 (gdb+0x423ce8) (BuildId: 6dc308d9bc2da51d7adf979315fabd66fb46e8a3)

SUMMARY: ThreadSanitizer: data race /home/vries/gdb/src/gdb/dwarf2/index-cache.c:76 in index_cache::enable()
==================
(gdb) FAIL: gdb.base/index-cache.exp: test_basic_stuff: enable index cache
...
Comment 1 Tom de Vries 2024-01-18 12:37:45 UTC
I guess the problem is that we're capturing index_cache_store_context in a worker thread (T5) while the capturing is supposed to happen in the main thread:
...
/* Information to be captured in the main thread, and to be used by worker                                            
   threads during store ().  */

struct index_cache_store_context
{
  friend class index_cache;

  index_cache_store_context (const index_cache &ic, dwarf2_per_bfd *per_bfd);
...

In other words, this should trigger:
...
diff --git a/gdb/dwarf2/index-cache.c b/gdb/dwarf2/index-cache.c
index 7ddd7b3f974..50db5f92b40 100644
--- a/gdb/dwarf2/index-cache.c
+++ b/gdb/dwarf2/index-cache.c
@@ -92,6 +92,7 @@ index_cache_store_context::index_cache_store_context (const index_cache &ic,
 						      dwarf2_per_bfd *per_bfd)
   :  m_enabled (ic.enabled ())
 {
+  gdb_assert (is_main_thread ());
   if (!m_enabled)
     return;
 
...
Comment 2 Tom de Vries 2024-01-22 14:17:39 UTC
Bisects to:
...
commit 33c6eaaefcedd45e86d564d014f14cce2620f933
Author: Tom Tromey <tom@tromey.com>
Date:   Fri Mar 24 23:35:02 2023 -0600

    Do more DWARF reading in the background
...
Comment 3 Tom Tromey 2024-01-27 16:09:46 UTC
I found another bug here (the cache directory isn't captured)
and I have a series to clean this all up now.
Comment 5 Sourceware Commits 2024-03-09 00:27:41 UTC
The master branch has been updated by Tom Tromey <tromey@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=ed29a346be439466ff2a5ce33e715e02c49fbdac

commit ed29a346be439466ff2a5ce33e715e02c49fbdac
Author: Tom Tromey <tom@tromey.com>
Date:   Sun Jan 28 09:14:04 2024 -0700

    Avoid race when writing to index cache
    
    The background DWARF reader changes introduced a race when writing to
    the index cache.  The problem here is that constructing the
    index_cache_store_context object should only happen on the main
    thread, to ensure that the various value captures do not race.
    
    This patch adds an assert to the construct to that effect, and then
    arranges for this object to be constructed by the cooked_index_worker
    constructor -- which is only invoked on the main thread.
    
    Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=31262
Comment 6 Tom Tromey 2024-03-09 00:28:11 UTC
Fixed.