Bug 30392 - [gdb/symtab] thread sanitizer data race in gdb.base/index-cache.exp
Summary: [gdb/symtab] thread sanitizer data race in gdb.base/index-cache.exp
Status: RESOLVED FIXED
Alias: None
Product: gdb
Classification: Unclassified
Component: symtab (show other bugs)
Version: HEAD
: P2 normal
Target Milestone: 14.1
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2023-04-26 17:34 UTC by Tom de Vries
Modified: 2023-08-04 13:10 UTC (History)
3 users (show)

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


Attachments
offending gdb.log (14.24 KB, text/x-log)
2023-04-26 17:35 UTC, Tom de Vries
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Tom de Vries 2023-04-26 17:34:46 UTC
When building gdb with thread sanitizer, I get in test-case gdb.base/index-cache.exp:
...
(gdb) PASS: gdb.base/index-cache.exp: test_basic_stuff: index-cache is disabled by default
set index-cache enabled on^M
==================^M
^[[1m^[[31mWARNING: ThreadSanitizer: data race (pid=6153)^M
^[[1m^[[0m^[[1m^[[34m  Write of size 1 at 0x000003197b80 by main thread:^M
^[[1m^[[0m    #0 index_cache::enable() /data/vries/gdb/src/gdb/dwarf2/index-cache.c:76 (gdb+0x8247db)^M
...
Comment 1 Tom de Vries 2023-04-26 17:35:28 UTC
Created attachment 14852 [details]
offending gdb.log
Comment 2 Tom Tromey 2023-04-27 23:27:12 UTC
The reader probably should capture the necessarily globals
on the main thread and stash them until the index has been
written.
Comment 3 Simon Marchi 2023-04-28 14:30:24 UTC
(In reply to Tom Tromey from comment #2)
> The reader probably should capture the necessarily globals
> on the main thread and stash them until the index has been
> written.

I tried to look into it, but then gave up.

The first issue we hit (the failure Tom de Vries shows) is an unprotected access to global_index_cache::m_enabled.  That is easily fixed by making m_enabled an std::atomic<bool> (don't know if that's the right way, but it makes tsan happy).

But then tsan reports some concurrent protected accesses to the struct bfd, the first one being:

WARNING: ThreadSanitizer: data race (pid=25465)
  Write of size 4 at 0x7b440007ca08 by main thread:
    #0 bfd_open_file /home/smarchi/src/binutils-gdb/bfd/cache.c:584 (gdb+0x5b84833)
    #1 bfd_cache_lookup_worker /home/smarchi/src/binutils-gdb/bfd/cache.c:261 (gdb+0x5b83d27)
    #2 cache_bseek /home/smarchi/src/binutils-gdb/bfd/cache.c:289 (gdb+0x5b83f3d)
    #3 bfd_seek /home/smarchi/src/binutils-gdb/bfd/bfdio.c:400 (gdb+0x5b8275e)
    #4 _bfd_generic_get_section_contents /home/smarchi/src/binutils-gdb/bfd/libbfd.c:958 (gdb+0x5b90887)
    #5 bfd_get_section_contents /home/smarchi/src/binutils-gdb/bfd/section.c:1588 (gdb+0x5ba5a05)
    #6 gdb_bfd_scan_elf_dyntag(int, bfd*, unsigned long*, unsigned long*) /home/smarchi/src/binutils-gdb/gdb/solib.c:1583 (gdb+0x52d1f84)
    #7 elf_locate_base /home/smarchi/src/binutils-gdb/gdb/solib-svr4.c:705 (gdb+0x528c740)
    #8 svr4_iterate_over_objfiles_in_search_order /home/smarchi/src/binutils-gdb/gdb/solib-svr4.c:3434 (gdb+0x529e67b)
    #9 gdbarch_iterate_over_objfiles_in_search_order(gdbarch*, gdb::function_view<bool (objfile*)>, objfile*) /home/smarchi/src/binutils-gdb/gdb/gdbarch.c:5041 (gdb+0x3881886)
    #10 find_main_name /home/smarchi/src/binutils-gdb/gdb/symtab.c:6266 (gdb+0x545e340)
    #11 main_language() /home/smarchi/src/binutils-gdb/gdb/symtab.c:6309 (gdb+0x545e572)
    #12 set_initial_language() /home/smarchi/src/binutils-gdb/gdb/symfile.c:1697 (gdb+0x53b898a)
    #13 symbol_file_add_main_1 /home/smarchi/src/binutils-gdb/gdb/symfile.c:1213 (gdb+0x53b6553)
    #14 symbol_file_command(char const*, int) /home/smarchi/src/binutils-gdb/gdb/symfile.c:1678 (gdb+0x53b88d7)
    #15 file_command /home/smarchi/src/binutils-gdb/gdb/exec.c:554 (gdb+0x455cb55)
    ...

  Previous read of size 1 at 0x7b440007ca08 by thread T3:
    #0 bfd_check_format_matches /home/smarchi/src/binutils-gdb/bfd/format.c:323 (gdb+0x5b8be0b)
    #1 bfd_check_format /home/smarchi/src/binutils-gdb/bfd/format.c:94 (gdb+0x5b8b112)
    #2 build_id_bfd_get(bfd*) /home/smarchi/src/binutils-gdb/gdb/build-id.c:41 (gdb+0x3b86056)
    #3 index_cache::store(dwarf2_per_bfd*) /home/smarchi/src/binutils-gdb/gdb/dwarf2/index-cache.c:99 (gdb+0x4143a9b)
    #4 cooked_index::maybe_write_index(dwarf2_per_bfd*) /home/smarchi/src/binutils-gdb/gdb/dwarf2/cooked-index.c:638 (gdb+0x4054df7)
    #5 operator() /home/smarchi/src/binutils-gdb/gdb/dwarf2/cooked-index.c:468 (gdb+0x4052926)
    ...

The main thread writes to

  unsigned int cacheable : 1;

and the worker thread reads:

  ENUM_BITFIELD (bfd_direction) direction : 2;

These two bitfields are within the same integer storage.

I tried to change it so that cooked_index::start_writing_index would fetch everything that the worker thread could possibly need in the bfds (the objfile's bfd, and the potential dwz bfd) and pass it to the worker thread, so make it so the worker thread would never access the bfd.  I then added some gdb_assert to ensure the worker thread would never try to fetch the bfd from dwarf2_per_bfd.  Making the obfd field private, and adding a getter with:

  gdb_assert (is_main_thread ());

Then, tsan pointed out that calling gdb_assert on the worker thread is racy, because gdb_assert uses some globals: current_ui, and current_inferior, to make the target_supports_terminal_ours call.  The worker threads should really avoid touching those.

I then went into the rabbit hole of trying to make calling gdb_assert on the worker thread tsan-clean, even if it meant that a failed assertion would just straight up abort the process (no question, no backtrace).  There was always something going wrong, so I eventually just gave up.

I could give another try, just focusing on the index-cache issue, no trying to solve all problems at once.  It would still be nice to make gdb_assert safe for worker threads eventually though.
Comment 4 Tom de Vries 2023-07-25 12:27:42 UTC
(In reply to Simon Marchi from comment #3)
> (In reply to Tom Tromey from comment #2)
> > The reader probably should capture the necessarily globals
> > on the main thread and stash them until the index has been
> > written.
> 
> I tried to look into it, but then gave up.
> 
> The first issue we hit (the failure Tom de Vries shows) is an unprotected
> access to global_index_cache::m_enabled.  That is easily fixed by making
> m_enabled an std::atomic<bool> (don't know if that's the right way, but it
> makes tsan happy).

This tries the idea of caputuring the value of global_index_cache::m_enabled on cooked_index construction:
...
diff --git a/gdb/dwarf2/cooked-index.c b/gdb/dwarf2/cooked-index.c
index 25635d9b72e..d331abe08fd 100644
--- a/gdb/dwarf2/cooked-index.c
+++ b/gdb/dwarf2/cooked-index.c
@@ -446,6 +446,8 @@ cooked_index_shard::wait (bool allow_quit) const
 cooked_index::cooked_index (vec_type &&vec)
   : m_vector (std::move (vec))
 {
+  m_global_index_cache_enabled = global_index_cache.enabled ();
+
   for (auto &idx : m_vector)
     idx->finalize ();
 
@@ -635,7 +637,8 @@ cooked_index::maybe_write_index (dwarf2_per_bfd *per_bfd)

   wait ();
 
   /* (maybe) store an index in the cache.  */
-  global_index_cache.store (per_bfd);
+  if (m_global_index_cache_enabled)
+    global_index_cache.store (per_bfd);
 }
 
 /* Wait for all the index cache entries to be written before gdb
diff --git a/gdb/dwarf2/cooked-index.h b/gdb/dwarf2/cooked-index.h
index 0d6f3e5aa0e..e1454c97ba4 100644
--- a/gdb/dwarf2/cooked-index.h
+++ b/gdb/dwarf2/cooked-index.h
@@ -443,6 +443,8 @@ class cooked_index : public dwarf_scanner_base
 
   /* A future that tracks when the 'index_write' method is done.  */
   gdb::future<void> m_write_future;
+
+  bool m_global_index_cache_enabled;
 };
 
 #endif /* GDB_DWARF2_COOKED_INDEX_H */
diff --git a/gdb/dwarf2/index-cache.c b/gdb/dwarf2/index-cache.c
index 79ab706ee9d..790aa52ea02 100644
--- a/gdb/dwarf2/index-cache.c
+++ b/gdb/dwarf2/index-cache.c
@@ -91,9 +91,6 @@ index_cache::disable ()
 voide--
 index_cache::store (dwarf2_per_bfd *per_bfd)
 {
-  if (!enabled ())
-    return;
-
   /* Get build id of objfile.  */
   const bfd_build_id *build_id = build_id_bfd_get (per_bfd->obfd);
   if (build_id == nullptr)
...
and that fixes that particular data race.
Comment 5 Tom de Vries 2023-07-28 08:58:56 UTC
Posted an RFC ( https://sourceware.org/pipermail/gdb-patches/2023-July/201189.html ).
Comment 6 Tom de Vries 2023-07-28 09:32:42 UTC
(In reply to Simon Marchi from comment #3)
> The first issue we hit (the failure Tom de Vries shows) is an unprotected
> access to global_index_cache::m_enabled.  That is easily fixed by making
> m_enabled an std::atomic<bool> (don't know if that's the right way, but it
> makes tsan happy).

FWIW, AFAIU, the problem is that we have:
...
(gdb) set index-cache enabled off
(gdb) file $exec
(gdb) set index-cache enabled on
...
and there's a race on global_index_cache::m_enabled, with:
- the "set index-cache enabled on" command writing it, and
- the index-cache entry writing scheduled by the file command reading it.

If the read happens first, no index-cache entry will be written.  If the write happens first, an index-cache-entry will be written.

By making it a std::atomic<bool>, we make this non-determinism defined behaviour, so tsan stops complaining, but we want deterministic behaviour instead.
Comment 7 Tom de Vries 2023-07-28 09:36:35 UTC
(In reply to Simon Marchi from comment #3)
>     #2 build_id_bfd_get(bfd*)
> /home/smarchi/src/binutils-gdb/gdb/build-id.c:41 (gdb+0x3b86056)
>     #3 index_cache::store(dwarf2_per_bfd*)
> /home/smarchi/src/binutils-gdb/gdb/dwarf2/index-cache.c:99 (gdb+0x4143a9b)
>     #4 cooked_index::maybe_write_index(dwarf2_per_bfd*)

In the RFC I've posted, I've addressed this by capturing the build id string (and likewise for the dwz one) in the main thread, such that index_cache::store no longer needs to access the bfd for this purpose.
Comment 8 Sourceware Commits 2023-08-04 13:03:02 UTC
The master branch has been updated by Tom de Vries <vries@sourceware.org>:

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

commit 8adc5522280c06c1c750185af0dc5a8461d9a13f
Author: Tom de Vries <tdevries@suse.de>
Date:   Fri Aug 4 15:02:43 2023 +0200

    [gdb/symtab] Fix data race on index_cache::m_enabled
    
    With gdb build with -fsanitize=thread and test-case gdb.base/index-cache.exp I
    run into:
    ...
    (gdb) file build/gdb/testsuite/outputs/gdb.base/index-cache/index-cache
    Reading symbols from build/gdb/testsuite/outputs/gdb.base/index-cache/index-cache...
    (gdb) show index-cache enabled
    The index cache is off.
    (gdb) PASS: gdb.base/index-cache.exp: test_basic_stuff: index-cache is disabled by default
    set index-cache enabled on
    ==================
    WARNING: ThreadSanitizer: data race (pid=32248)
      Write of size 1 at 0x00000321f540 by main thread:
        #0 index_cache::enable() gdb/dwarf2/index-cache.c:76 (gdb+0x82cfdd)
        #1 set_index_cache_enabled_command gdb/dwarf2/index-cache.c:270 (gdb+0x82d9af)
        #2 bool setting::set<bool>(bool const&) gdb/command.h:353 (gdb+0x6fe5f2)
        #3 do_set_command(char const*, int, cmd_list_element*) gdb/cli/cli-setshow.c:414 (gdb+0x6fcd21)
        #4 execute_command(char const*, int) gdb/top.c:567 (gdb+0xff2e64)
        #5 command_handler(char const*) gdb/event-top.c:552 (gdb+0x94acc0)
        #6 command_line_handler(std::unique_ptr<char, gdb::xfree_deleter<char> >&&) gdb/event-top.c:788 (gdb+0x94b37d)
        #7 tui_command_line_handler gdb/tui/tui-interp.c:104 (gdb+0x103467e)
        #8 gdb_rl_callback_handler gdb/event-top.c:259 (gdb+0x94a265)
        #9 rl_callback_read_char readline/readline/callback.c:290 (gdb+0x11bdd3f)
        #10 gdb_rl_callback_read_char_wrapper_noexcept gdb/event-top.c:195 (gdb+0x94a064)
        #11 gdb_rl_callback_read_char_wrapper gdb/event-top.c:234 (gdb+0x94a125)
        #12 stdin_event_handler gdb/ui.c:155 (gdb+0x1074922)
        #13 handle_file_event gdbsupport/event-loop.cc:573 (gdb+0x1d94de4)
        #14 gdb_wait_for_event gdbsupport/event-loop.cc:694 (gdb+0x1d9551c)
        #15 gdb_do_one_event(int) gdbsupport/event-loop.cc:264 (gdb+0x1d93908)
        #16 start_event_loop gdb/main.c:412 (gdb+0xb5a256)
        #17 captured_command_loop gdb/main.c:476 (gdb+0xb5a445)
        #18 captured_main gdb/main.c:1320 (gdb+0xb5c5c5)
        #19 gdb_main(captured_main_args*) gdb/main.c:1339 (gdb+0xb5c674)
        #20 main gdb/gdb.c:32 (gdb+0x416776)
    
      Previous read of size 1 at 0x00000321f540 by thread T12:
        #0 index_cache::enabled() const gdb/dwarf2/index-cache.h:48 (gdb+0x82e1a6)
        #1 index_cache::store(dwarf2_per_bfd*) gdb/dwarf2/index-cache.c:94 (gdb+0x82d0bc)
        #2 cooked_index::maybe_write_index(dwarf2_per_bfd*) gdb/dwarf2/cooked-index.c:638 (gdb+0x7f1b97)
        #3 operator() gdb/dwarf2/cooked-index.c:468 (gdb+0x7f0f24)
        #4 _M_invoke /usr/include/c++/7/bits/std_function.h:316 (gdb+0x7f285b)
        #5 std::function<void ()>::operator()() const /usr/include/c++/7/bits/std_function.h:706 (gdb+0x700952)
        #6 void std::__invoke_impl<void, std::function<void ()>&>(std::__invoke_other, std::function<void ()>&) /usr/include/c++/7/bits/invoke.h:60 (gdb+0x7381a0)
        #7 std::__invoke_result<std::function<void ()>&>::type std::__invoke<std::function<void ()>&>(std::function<void ()>&) /usr/include/c++/7/bits/invoke.h:95 (gdb+0x737e91)
        #8 std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run()::{lambda()#1}::operator()() const /usr/include/c++/7/future:1421 (gdb+0x737b59)
        #9 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++/7/future:1362 (gdb+0x738660)
        #10 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++/7/bits/std_function.h:302 (gdb+0x73825c)
        #11 std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>::operator()() const /usr/include/c++/7/bits/std_function.h:706 (gdb+0x733623)
        #12 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++/7/future:561 (gdb+0x732bdf)
        #13 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++/7/bits/invoke.h:73 (gdb+0x734c4f)
        #14 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++/7/bits/invoke.h:95 (gdb+0x733bc5)
        #15 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++/7/mutex:672 (gdb+0x73300d)
        #16 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()#2}::operator()() const /usr/include/c++/7/mutex:677 (gdb+0x7330b2)
        #17 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()#2}::_FUN() /usr/include/c++/7/mutex:677 (gdb+0x7330f2)
        #18 pthread_once <null> (libtsan.so.0+0x4457c)
        #19 __gthread_once /usr/include/c++/7/x86_64-suse-linux/bits/gthr-default.h:699 (gdb+0x72f5dd)
        #20 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++/7/mutex:684 (gdb+0x733224)
        #21 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++/7/future:401 (gdb+0x732852)
        #22 std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run() /usr/include/c++/7/future:1423 (gdb+0x737bef)
        #23 std::packaged_task<void ()>::operator()() /usr/include/c++/7/future:1556 (gdb+0x1dac492)
        #24 gdb::thread_pool::thread_function() gdbsupport/thread-pool.cc:242 (gdb+0x1dabdb4)
        #25 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++/7/bits/invoke.h:73 (gdb+0x1dace63)
        #26 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++/7/bits/invoke.h:95 (gdb+0x1dac294)
        #27 decltype (__invoke((_S_declval<0ul>)(), (_S_declval<1ul>)())) std::thread::_Invoker<std::tuple<void (gdb::thread_pool::*)(), gdb::thread_pool*> >::_M_invoke<0ul, 1ul>(std::_Index_tuple<0ul, 1ul>) /usr/include/c++/7/thread:234 (gdb+0x1daf5c6)
        #28 std::thread::_Invoker<std::tuple<void (gdb::thread_pool::*)(), gdb::thread_pool*> >::operator()() /usr/include/c++/7/thread:243 (gdb+0x1daf551)
        #29 std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (gdb::thread_pool::*)(), gdb::thread_pool*> > >::_M_run() /usr/include/c++/7/thread:186 (gdb+0x1daf506)
        #30 <null> <null> (libstdc++.so.6+0xdcac2)
    
      Location is global 'global_index_cache' of size 48 at 0x00000321f520 (gdb+0x00000321f540)
      ...
    SUMMARY: ThreadSanitizer: data race gdb/dwarf2/index-cache.c:76 in index_cache::enable()
    ...
    
    The race happens when issuing a "file $exec" command followed by a
    "set index-cache enabled on" command.
    
    The race is between:
    - a worker thread reading index_cache::m_enabled to determine whether an
      index-cache entry for $exec needs to be written
      (due to command "file $exec"), and
    - the main thread setting index_cache::m_enabled
      (due to command "set index-cache enabled on").
    
    Fix this by capturing the value of index_cache::m_enabled in the main thread,
    and using the captured value in the worker thread.
    
    Tested on x86_64-linux.
    
    PR symtab/30392
    Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=30392
Comment 9 Sourceware Commits 2023-08-04 13:03:07 UTC
The master branch has been updated by Tom de Vries <vries@sourceware.org>:

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

commit 488b3ff1fc70a3a5fb7cfc33378be62fffdea7fd
Author: Tom de Vries <tdevries@suse.de>
Date:   Fri Aug 4 15:02:43 2023 +0200

    [gdb/symtab] Fix data race on bfd::{cacheable,format}
    
    With gdb build with -fsanitize=thread and test-case gdb.base/index-cache.exp I
    run into:
    ...
    (gdb) file build/gdb/testsuite/outputs/gdb.base/index-cache/index-cache
    Reading symbols from build/gdb/testsuite/outputs/gdb.base/index-cache/index-cache...
    ==================
    WARNING: ThreadSanitizer: data race (pid=12261)
      Write of size 4 at 0x7b4400097d08 by main thread:
        #0 bfd_open_file bfd/cache.c:584 (gdb+0x148bb92)
        #1 bfd_cache_lookup_worker bfd/cache.c:261 (gdb+0x148b12a)
        #2 cache_bseek bfd/cache.c:289 (gdb+0x148b324)
        #3 bfd_seek bfd/bfdio.c:459 (gdb+0x1489c31)
        #4 _bfd_generic_get_section_contents bfd/libbfd.c:1069 (gdb+0x14977a4)
        #5 bfd_get_section_contents bfd/section.c:1606 (gdb+0x149cc7c)
        #6 gdb_bfd_scan_elf_dyntag(int, bfd*, unsigned long*, unsigned long*) gdb/solib.c:1601 (gdb+0xed8eca)
        #7 elf_locate_base gdb/solib-svr4.c:705 (gdb+0xec28ac)
        #8 svr4_iterate_over_objfiles_in_search_order gdb/solib-svr4.c:3430 (gdb+0xeca55d)
        #9 gdbarch_iterate_over_objfiles_in_search_order(gdbarch*, gdb::function_view<bool (objfile*)>, objfile*) gdb/gdbarch.c:5041 (gdb+0x537cad)
        #10 find_main_name gdb/symtab.c:6270 (gdb+0xf743a5)
        #11 main_language() gdb/symtab.c:6313 (gdb+0xf74499)
        #12 set_initial_language() gdb/symfile.c:1700 (gdb+0xf4285c)
        #13 symbol_file_add_main_1 gdb/symfile.c:1212 (gdb+0xf40e2a)
        #14 symbol_file_command(char const*, int) gdb/symfile.c:1681 (gdb+0xf427d1)
        #15 file_command gdb/exec.c:554 (gdb+0x94f74b)
        #16 do_simple_func gdb/cli/cli-decode.c:95 (gdb+0x6d9528)
        #17 cmd_func(cmd_list_element*, char const*, int) gdb/cli/cli-decode.c:2735 (gdb+0x6e0f69)
        #18 execute_command(char const*, int) gdb/top.c:575 (gdb+0xff303c)
        #19 command_handler(char const*) gdb/event-top.c:552 (gdb+0x94adde)
        #20 command_line_handler(std::unique_ptr<char, gdb::xfree_deleter<char> >&&) gdb/event-top.c:788 (gdb+0x94b49b)
        #21 tui_command_line_handler gdb/tui/tui-interp.c:104 (gdb+0x103479c)
        #22 gdb_rl_callback_handler gdb/event-top.c:259 (gdb+0x94a383)
        #23 rl_callback_read_char readline/readline/callback.c:290 (gdb+0x11bde5d)
        #24 gdb_rl_callback_read_char_wrapper_noexcept gdb/event-top.c:195 (gdb+0x94a182)
        #25 gdb_rl_callback_read_char_wrapper gdb/event-top.c:234 (gdb+0x94a243)
        #26 stdin_event_handler gdb/ui.c:155 (gdb+0x1074a40)
        #27 handle_file_event gdbsupport/event-loop.cc:573 (gdb+0x1d94f02)
        #28 gdb_wait_for_event gdbsupport/event-loop.cc:694 (gdb+0x1d9563a)
        #29 gdb_do_one_event(int) gdbsupport/event-loop.cc:264 (gdb+0x1d93a26)
        #30 start_event_loop gdb/main.c:412 (gdb+0xb5a374)
        #31 captured_command_loop gdb/main.c:476 (gdb+0xb5a563)
        #32 captured_main gdb/main.c:1320 (gdb+0xb5c6e3)
        #33 gdb_main(captured_main_args*) gdb/main.c:1339 (gdb+0xb5c792)
        #34 main gdb/gdb.c:32 (gdb+0x416776)
    
      Previous read of size 1 at 0x7b4400097d08 by thread T12:
        #0 bfd_check_format_matches bfd/format.c:323 (gdb+0x1492db4)
        #1 bfd_check_format bfd/format.c:94 (gdb+0x1492104)
        #2 build_id_bfd_get(bfd*) gdb/build-id.c:42 (gdb+0x6648f7)
        #3 index_cache::store(dwarf2_per_bfd*, index_cache_store_context*) gdb/dwarf2/index-cache.c:110 (gdb+0x82d205)
        #4 cooked_index::maybe_write_index(dwarf2_per_bfd*) gdb/dwarf2/cooked-index.c:640 (gdb+0x7f1bf1)
        #5 operator() gdb/dwarf2/cooked-index.c:470 (gdb+0x7f0f40)
        #6 _M_invoke /usr/include/c++/7/bits/std_function.h:316 (gdb+0x7f28f7)
        #7 std::function<void ()>::operator()() const /usr/include/c++/7/bits/std_function.h:706 (gdb+0x700952)
        #8 void std::__invoke_impl<void, std::function<void ()>&>(std::__invoke_other, std::function<void ()>&) /usr/include/c++/7/bits/invoke.h:60 (gdb+0x7381a0)
        #9 std::__invoke_result<std::function<void ()>&>::type std::__invoke<std::function<void ()>&>(std::function<void ()>&) /usr/include/c++/7/bits/invoke.h:95 (gdb+0x737e91)
        #10 std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run()::{lambda()#1}::operator()() const /usr/include/c++/7/future:1421 (gdb+0x737b59)
        #11 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++/7/future:1362 (gdb+0x738660)
        #12 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++/7/bits/std_function.h:302 (gdb+0x73825c)
        #13 std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>::operator()() const /usr/include/c++/7/bits/std_function.h:706 (gdb+0x733623)
        #14 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++/7/future:561 (gdb+0x732bdf)
        #15 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++/7/bits/invoke.h:73 (gdb+0x734c4f)
        #16 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++/7/bits/invoke.h:95 (gdb+0x733bc5)
        #17 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++/7/mutex:672 (gdb+0x73300d)
        #18 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()#2}::operator()() const /usr/include/c++/7/mutex:677 (gdb+0x7330b2)
        #19 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()#2}::_FUN() /usr/include/c++/7/mutex:677 (gdb+0x7330f2)
        #20 pthread_once <null> (libtsan.so.0+0x4457c)
        #21 __gthread_once /usr/include/c++/7/x86_64-suse-linux/bits/gthr-default.h:699 (gdb+0x72f5dd)
        #22 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++/7/mutex:684 (gdb+0x733224)
        #23 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++/7/future:401 (gdb+0x732852)
        #24 std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run() /usr/include/c++/7/future:1423 (gdb+0x737bef)
        #25 std::packaged_task<void ()>::operator()() /usr/include/c++/7/future:1556 (gdb+0x1dac5b0)
        #26 gdb::thread_pool::thread_function() gdbsupport/thread-pool.cc:242 (gdb+0x1dabed2)
        #27 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++/7/bits/invoke.h:73 (gdb+0x1dacf81)
        #28 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++/7/bits/invoke.h:95 (gdb+0x1dac3b2)
        #29 decltype (__invoke((_S_declval<0ul>)(), (_S_declval<1ul>)())) std::thread::_Invoker<std::tuple<void (gdb::thread_pool::*)(), gdb::thread_pool*> >::_M_invoke<0ul, 1ul>(std::_Index_tuple<0ul, 1ul>) /usr/include/c++/7/thread:234 (gdb+0x1daf6e4)
        #30 std::thread::_Invoker<std::tuple<void (gdb::thread_pool::*)(), gdb::thread_pool*> >::operator()() /usr/include/c++/7/thread:243 (gdb+0x1daf66f)
        #31 std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (gdb::thread_pool::*)(), gdb::thread_pool*> > >::_M_run() /usr/include/c++/7/thread:186 (gdb+0x1daf624)
        #32 <null> <null> (libstdc++.so.6+0xdcac2)
      ...
    SUMMARY: ThreadSanitizer: data race bfd/cache.c:584 in bfd_open_file
    ...
    
    The race happens when issuing the "file $exec" command.
    
    The race is between:
    - a worker thread getting the build id while writing the index cache, and in
      the process reading bfd::format, and
    - the main thread calling find_main_name, and in the process setting
      bfd::cacheable.
    
    The two bitfields bfd::cacheable and bfd::format share the same bitfield
    container.
    
    Fix this by capturing the build id in the main thread, and using the captured
    value in the worker thread.
    
    Likewise for the dwz build id, which likely suffers from the same issue.
    
    While we're at it, also move the creation of the cache directory to
    the index_cache_store_context constructor, to:
    - make sure there's no race between subsequent file commands, and
    - issue any related warning or error messages during the file command.
    
    Tested on x86_64-linux.
    
    Approved-By: Tom Tromey <tom@tromey.com>
    
    PR symtab/30392
    Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=30392
Comment 10 Sourceware Commits 2023-08-04 13:03:12 UTC
The master branch has been updated by Tom de Vries <vries@sourceware.org>:

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

commit 12afdeecc916e72ced0d614a20cb4d6ad47c17e7
Author: Tom de Vries <tdevries@suse.de>
Date:   Fri Aug 4 15:02:43 2023 +0200

    [gdb/symtab] Fix race on dwarf2_per_cu_data::{queued,is_debug_type}
    
    With gdb build with -fsanitize=thread and test-case gdb.base/index-cache.exp I
    run into:
    ...
    (gdb) file build/gdb/testsuite/outputs/gdb.base/index-cache/index-cache
    Reading symbols from build/gdb/testsuite/outputs/gdb.base/index-cache/index-cache...
    ==================
    WARNING: ThreadSanitizer: data race (pid=24296)
      Write of size 1 at 0x7b200000420d by main thread:
        #0 queue_comp_unit gdb/dwarf2/read.c:5564 (gdb+0x8939ce)
        #1 dw2_do_instantiate_symtab gdb/dwarf2/read.c:1754 (gdb+0x885b96)
        #2 dw2_instantiate_symtab gdb/dwarf2/read.c:1792 (gdb+0x885d86)
        #3 dw2_expand_symtabs_matching_one(dwarf2_per_cu_data*, dwarf2_per_objfile*, gdb::function_view<bool (char const*, bool)>, gdb::function_view<bool (compunit_symtab*)>) gdb/dwarf2/read.c:3042 (gdb+0x88ac77)
        #4 cooked_index_functions::expand_symtabs_matching(objfile*, gdb::function_view<bool (char const*, bool)>, lookup_name_info const*, gdb::function_view<bool (char const*)>, gdb::function_view<bool (compunit_symtab*)>, enum_flags<block_search_flag_values>, domain_enum, search_domain) gdb/dwarf2/read.c:16915 (gdb+0x8c1c8a)
        #5 objfile::lookup_symbol(block_enum, char const*, domain_enum) gdb/symfile-debug.c:288 (gdb+0xf389a1)
        #6 lookup_symbol_via_quick_fns gdb/symtab.c:2385 (gdb+0xf66403)
        #7 lookup_symbol_in_objfile gdb/symtab.c:2516 (gdb+0xf66a67)
        #8 operator() gdb/symtab.c:2562 (gdb+0xf66bbe)
        #9 operator() gdb/../gdbsupport/function-view.h:305 (gdb+0xf76ffd)
        #10 _FUN gdb/../gdbsupport/function-view.h:299 (gdb+0xf77054)
        #11 gdb::function_view<bool (objfile*)>::operator()(objfile*) const gdb/../gdbsupport/function-view.h:289 (gdb+0xc3f5e3)
        #12 svr4_iterate_over_objfiles_in_search_order gdb/solib-svr4.c:3455 (gdb+0xeca793)
        #13 gdbarch_iterate_over_objfiles_in_search_order(gdbarch*, gdb::function_view<bool (objfile*)>, objfile*) gdb/gdbarch.c:5041 (gdb+0x537cad)
        #14 lookup_global_or_static_symbol gdb/symtab.c:2559 (gdb+0xf66e47)
        #15 lookup_global_symbol(char const*, block const*, domain_enum) gdb/symtab.c:2615 (gdb+0xf670cc)
        #16 language_defn::lookup_symbol_nonlocal(char const*, block const*, domain_enum) const gdb/symtab.c:2447 (gdb+0xf666ba)
        #17 lookup_symbol_aux gdb/symtab.c:2123 (gdb+0xf655ff)
        #18 lookup_symbol_in_language(char const*, block const*, domain_enum, language, field_of_this_result*) gdb/symtab.c:1931 (gdb+0xf646f7)
        #19 set_initial_language() gdb/symfile.c:1708 (gdb+0xf429c0)
        #20 symbol_file_add_main_1 gdb/symfile.c:1212 (gdb+0xf40f54)
        #21 symbol_file_command(char const*, int) gdb/symfile.c:1681 (gdb+0xf428fb)
        #22 file_command gdb/exec.c:554 (gdb+0x94f875)
        #23 do_simple_func gdb/cli/cli-decode.c:95 (gdb+0x6d9528)
        #24 cmd_func(cmd_list_element*, char const*, int) gdb/cli/cli-decode.c:2735 (gdb+0x6e0f69)
        #25 execute_command(char const*, int) gdb/top.c:575 (gdb+0xff3166)
        #26 command_handler(char const*) gdb/event-top.c:552 (gdb+0x94af08)
        #27 command_line_handler(std::unique_ptr<char, gdb::xfree_deleter<char> >&&) gdb/event-top.c:788 (gdb+0x94b5c5)
        #28 tui_command_line_handler gdb/tui/tui-interp.c:104 (gdb+0x10348c6)
        #29 gdb_rl_callback_handler gdb/event-top.c:259 (gdb+0x94a4ad)
        #30 rl_callback_read_char readline/readline/callback.c:290 (gdb+0x11bdf87)
        #31 gdb_rl_callback_read_char_wrapper_noexcept gdb/event-top.c:195 (gdb+0x94a2ac)
        #32 gdb_rl_callback_read_char_wrapper gdb/event-top.c:234 (gdb+0x94a36d)
        #33 stdin_event_handler gdb/ui.c:155 (gdb+0x1074b6a)
        #34 handle_file_event gdbsupport/event-loop.cc:573 (gdb+0x1d9502c)
        #35 gdb_wait_for_event gdbsupport/event-loop.cc:694 (gdb+0x1d95764)
        #36 gdb_do_one_event(int) gdbsupport/event-loop.cc:264 (gdb+0x1d93b50)
        #37 start_event_loop gdb/main.c:412 (gdb+0xb5a49e)
        #38 captured_command_loop gdb/main.c:476 (gdb+0xb5a68d)
        #39 captured_main gdb/main.c:1320 (gdb+0xb5c80d)
        #40 gdb_main(captured_main_args*) gdb/main.c:1339 (gdb+0xb5c8bc)
        #41 main gdb/gdb.c:32 (gdb+0x416776)
    
      Previous read of size 1 at 0x7b200000420d by thread T12:
        #0 write_gdbindex gdb/dwarf2/index-write.c:1229 (gdb+0x8310c8)
        #1 write_dwarf_index(dwarf2_per_bfd*, char const*, char const*, char const*, dw_index_kind) gdb/dwarf2/index-write.c:1484 (gdb+0x83232f)
        #2 index_cache::store(dwarf2_per_bfd*, index_cache_store_context*) gdb/dwarf2/index-cache.c:177 (gdb+0x82d62b)
        #3 cooked_index::maybe_write_index(dwarf2_per_bfd*) gdb/dwarf2/cooked-index.c:640 (gdb+0x7f1bf7)
        #4 operator() gdb/dwarf2/cooked-index.c:470 (gdb+0x7f0f40)
        #5 _M_invoke /usr/include/c++/7/bits/std_function.h:316 (gdb+0x7f2909)
        #6 std::function<void ()>::operator()() const /usr/include/c++/7/bits/std_function.h:706 (gdb+0x700952)
        #7 void std::__invoke_impl<void, std::function<void ()>&>(std::__invoke_other, std::function<void ()>&) /usr/include/c++/7/bits/invoke.h:60 (gdb+0x7381a0)
        #8 std::__invoke_result<std::function<void ()>&>::type std::__invoke<std::function<void ()>&>(std::function<void ()>&) /usr/include/c++/7/bits/invoke.h:95 (gdb+0x737e91)
        #9 std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run()::{lambda()#1}::operator()() const /usr/include/c++/7/future:1421 (gdb+0x737b59)
        #10 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++/7/future:1362 (gdb+0x738660)
        #11 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++/7/bits/std_function.h:302 (gdb+0x73825c)
        #12 std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>::operator()() const /usr/include/c++/7/bits/std_function.h:706 (gdb+0x733623)
        #13 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++/7/future:561 (gdb+0x732bdf)
        #14 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++/7/bits/invoke.h:73 (gdb+0x734c4f)
        #15 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++/7/bits/invoke.h:95 (gdb+0x733bc5)
        #16 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++/7/mutex:672 (gdb+0x73300d)
        #17 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()#2}::operator()() const /usr/include/c++/7/mutex:677 (gdb+0x7330b2)
        #18 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()#2}::_FUN() /usr/include/c++/7/mutex:677 (gdb+0x7330f2)
        #19 pthread_once <null> (libtsan.so.0+0x4457c)
        #20 __gthread_once /usr/include/c++/7/x86_64-suse-linux/bits/gthr-default.h:699 (gdb+0x72f5dd)
        #21 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++/7/mutex:684 (gdb+0x733224)
        #22 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++/7/future:401 (gdb+0x732852)
        #23 std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run() /usr/include/c++/7/future:1423 (gdb+0x737bef)
        #24 std::packaged_task<void ()>::operator()() /usr/include/c++/7/future:1556 (gdb+0x1dac6da)
        #25 gdb::thread_pool::thread_function() gdbsupport/thread-pool.cc:242 (gdb+0x1dabffc)
        #26 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++/7/bits/invoke.h:73 (gdb+0x1dad0ab)
        #27 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++/7/bits/invoke.h:95 (gdb+0x1dac4dc)
        #28 decltype (__invoke((_S_declval<0ul>)(), (_S_declval<1ul>)())) std::thread::_Invoker<std::tuple<void (gdb::thread_pool::*)(), gdb::thread_pool*> >::_M_invoke<0ul, 1ul>(std::_Index_tuple<0ul, 1ul>) /usr/include/c++/7/thread:234 (gdb+0x1daf80e)
        #29 std::thread::_Invoker<std::tuple<void (gdb::thread_pool::*)(), gdb::thread_pool*> >::operator()() /usr/include/c++/7/thread:243 (gdb+0x1daf799)
        #30 std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (gdb::thread_pool::*)(), gdb::thread_pool*> > >::_M_run() /usr/include/c++/7/thread:186 (gdb+0x1daf74e)
        #31 <null> <null> (libstdc++.so.6+0xdcac2)
     ...
    SUMMARY: ThreadSanitizer: data race gdb/dwarf2/read.c:5564 in queue_comp_unit
    ...
    
    The race happens when issuing the "file $exec" command.
    
    The race is between:
    - a worker thread writing the index cache, and in the process reading
      dwarf2_per_cu_data::is_debug_type, and
    - the main thread expanding the CU containing main, and in the process setting
      dwarf2_per_cu_data::queued.
    
    The two bitfields dwarf2_per_cu_data::queue and
    dwarf2_per_cu_data::is_debug_type share the same bitfield container.
    
    Fix this by making dwarf2_per_cu_data::queued a packed<bool, 1>.
    
    Tested on x86_64-linux.
    
    Approved-By: Tom Tromey <tom@tromey.com>
    
    PR symtab/30392
    Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=30392
Comment 11 Sourceware Commits 2023-08-04 13:03:18 UTC
The master branch has been updated by Tom de Vries <vries@sourceware.org>:

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

commit edb157dfc6a7c0918aa67439c4ea6fd6161f3841
Author: Tom de Vries <tdevries@suse.de>
Date:   Fri Aug 4 15:02:43 2023 +0200

    [gdb/symtab] Fix data race on dwarf2_per_cu_data::{m_header_read_in,is_debug_type}
    
    With gdb build with -fsanitize=thread and test-case gdb.base/index-cache.exp
    and target board debug-types, I run into:
    ...
    (gdb) file build/gdb/testsuite/outputs/gdb.base/index-cache/index-cache
    Reading symbols from build/gdb/testsuite/outputs/gdb.base/index-cache/index-cache...
    ==================
    WARNING: ThreadSanitizer: data race (pid=9654)
      Write of size 1 at 0x7b200000420d by main thread:
        #0 dwarf2_per_cu_data::get_header() const gdb/dwarf2/read.c:21513 (gdb+0x8d1eee)
        #1 dwarf2_per_cu_data::addr_size() const gdb/dwarf2/read.c:21524 (gdb+0x8d1f4e)
        #2 dwarf2_cu::addr_type() const gdb/dwarf2/cu.c:112 (gdb+0x806327)
        #3 set_die_type gdb/dwarf2/read.c:21932 (gdb+0x8d3870)
        #4 read_base_type gdb/dwarf2/read.c:15448 (gdb+0x8bcacb)
        #5 read_type_die_1 gdb/dwarf2/read.c:19832 (gdb+0x8cc0a5)
        #6 read_type_die gdb/dwarf2/read.c:19767 (gdb+0x8cbe6d)
        #7 lookup_die_type gdb/dwarf2/read.c:19739 (gdb+0x8cbdc7)
        #8 die_type gdb/dwarf2/read.c:19593 (gdb+0x8cb68a)
        #9 read_subroutine_type gdb/dwarf2/read.c:14648 (gdb+0x8b998e)
        #10 read_type_die_1 gdb/dwarf2/read.c:19792 (gdb+0x8cbf2f)
        #11 read_type_die gdb/dwarf2/read.c:19767 (gdb+0x8cbe6d)
        #12 read_func_scope gdb/dwarf2/read.c:10154 (gdb+0x8a4f36)
        #13 process_die gdb/dwarf2/read.c:6667 (gdb+0x898daa)
        #14 read_file_scope gdb/dwarf2/read.c:7682 (gdb+0x89bad8)
        #15 process_die gdb/dwarf2/read.c:6654 (gdb+0x898ced)
        #16 process_full_comp_unit gdb/dwarf2/read.c:6418 (gdb+0x8981de)
        #17 process_queue gdb/dwarf2/read.c:5690 (gdb+0x894433)
        #18 dw2_do_instantiate_symtab gdb/dwarf2/read.c:1770 (gdb+0x88623a)
        #19 dw2_instantiate_symtab gdb/dwarf2/read.c:1792 (gdb+0x886300)
        #20 dw2_expand_symtabs_matching_one(dwarf2_per_cu_data*, dwarf2_per_objfile*, gdb::function_view<bool (char const*, bool)>, gdb::function_view<bool (compunit_symtab*)>) gdb/dwarf2/read.c:3042 (gdb+0x88b1f1)
        #21 cooked_index_functions::expand_symtabs_matching(objfile*, gdb::function_view<bool (char const*, bool)>, lookup_name_info const*, gdb::function_view<bool (char const*)>, gdb::function_view<bool (compunit_symtab*)>, enum_flags<block_search_flag_values>, domain_enum, search_domain) gdb/dwarf2/read.c:16917 (gdb+0x8c228e)
        #22 objfile::lookup_symbol(block_enum, char const*, domain_enum) gdb/symfile-debug.c:288 (gdb+0xf39055)
        #23 lookup_symbol_via_quick_fns gdb/symtab.c:2385 (gdb+0xf66ab7)
        #24 lookup_symbol_in_objfile gdb/symtab.c:2516 (gdb+0xf6711b)
        #25 operator() gdb/symtab.c:2562 (gdb+0xf67272)
        #26 operator() gdb/../gdbsupport/function-view.h:305 (gdb+0xf776b1)
        #27 _FUN gdb/../gdbsupport/function-view.h:299 (gdb+0xf77708)
        #28 gdb::function_view<bool (objfile*)>::operator()(objfile*) const gdb/../gdbsupport/function-view.h:289 (gdb+0xc3fc97)
        #29 svr4_iterate_over_objfiles_in_search_order gdb/solib-svr4.c:3455 (gdb+0xecae47)
        #30 gdbarch_iterate_over_objfiles_in_search_order(gdbarch*, gdb::function_view<bool (objfile*)>, objfile*) gdb/gdbarch.c:5041 (gdb+0x537cad)
        #31 lookup_global_or_static_symbol gdb/symtab.c:2559 (gdb+0xf674fb)
        #32 lookup_global_symbol(char const*, block const*, domain_enum) gdb/symtab.c:2615 (gdb+0xf67780)
        #33 language_defn::lookup_symbol_nonlocal(char const*, block const*, domain_enum) const gdb/symtab.c:2447 (gdb+0xf66d6e)
        #34 lookup_symbol_aux gdb/symtab.c:2123 (gdb+0xf65cb3)
        #35 lookup_symbol_in_language(char const*, block const*, domain_enum, language, field_of_this_result*) gdb/symtab.c:1931 (gdb+0xf64dab)
        #36 set_initial_language() gdb/symfile.c:1708 (gdb+0xf43074)
        #37 symbol_file_add_main_1 gdb/symfile.c:1212 (gdb+0xf41608)
        #38 symbol_file_command(char const*, int) gdb/symfile.c:1681 (gdb+0xf42faf)
        #39 file_command gdb/exec.c:554 (gdb+0x94ff29)
        #40 do_simple_func gdb/cli/cli-decode.c:95 (gdb+0x6d9528)
        #41 cmd_func(cmd_list_element*, char const*, int) gdb/cli/cli-decode.c:2735 (gdb+0x6e0f69)
        #42 execute_command(char const*, int) gdb/top.c:575 (gdb+0xff379c)
        #43 command_handler(char const*) gdb/event-top.c:552 (gdb+0x94b5bc)
        #44 command_line_handler(std::unique_ptr<char, gdb::xfree_deleter<char> >&&) gdb/event-top.c:788 (gdb+0x94bc79)
        #45 tui_command_line_handler gdb/tui/tui-interp.c:104 (gdb+0x1034efc)
        #46 gdb_rl_callback_handler gdb/event-top.c:259 (gdb+0x94ab61)
        #47 rl_callback_read_char readline/readline/callback.c:290 (gdb+0x11be4ef)
        #48 gdb_rl_callback_read_char_wrapper_noexcept gdb/event-top.c:195 (gdb+0x94a960)
        #49 gdb_rl_callback_read_char_wrapper gdb/event-top.c:234 (gdb+0x94aa21)
        #50 stdin_event_handler gdb/ui.c:155 (gdb+0x10751a0)
        #51 handle_file_event gdbsupport/event-loop.cc:573 (gdb+0x1d95bac)
        #52 gdb_wait_for_event gdbsupport/event-loop.cc:694 (gdb+0x1d962e4)
        #53 gdb_do_one_event(int) gdbsupport/event-loop.cc:264 (gdb+0x1d946d0)
        #54 start_event_loop gdb/main.c:412 (gdb+0xb5ab52)
        #55 captured_command_loop gdb/main.c:476 (gdb+0xb5ad41)
        #56 captured_main gdb/main.c:1320 (gdb+0xb5cec1)
        #57 gdb_main(captured_main_args*) gdb/main.c:1339 (gdb+0xb5cf70)
        #58 main gdb/gdb.c:32 (gdb+0x416776)
    
      Previous read of size 1 at 0x7b200000420d by thread T11:
        #0 write_gdbindex gdb/dwarf2/index-write.c:1229 (gdb+0x831630)
        #1 write_dwarf_index(dwarf2_per_bfd*, char const*, char const*, char const*, dw_index_kind) gdb/dwarf2/index-write.c:1484 (gdb+0x832897)
        #2 index_cache::store(dwarf2_per_bfd*, index_cache_store_context const&) gdb/dwarf2/index-cache.c:173 (gdb+0x82db8d)
        #3 cooked_index::maybe_write_index(dwarf2_per_bfd*, index_cache_store_context const&) gdb/dwarf2/cooked-index.c:645 (gdb+0x7f1d49)
        #4 operator() gdb/dwarf2/cooked-index.c:474 (gdb+0x7f0f31)
        #5 _M_invoke /usr/include/c++/7/bits/std_function.h:316 (gdb+0x7f2a13)
        #6 std::function<void ()>::operator()() const /usr/include/c++/7/bits/std_function.h:706 (gdb+0x700952)
        #7 void std::__invoke_impl<void, std::function<void ()>&>(std::__invoke_other, std::function<void ()>&) /usr/include/c++/7/bits/invoke.h:60 (gdb+0x7381a0)
        #8 std::__invoke_result<std::function<void ()>&>::type std::__invoke<std::function<void ()>&>(std::function<void ()>&) /usr/include/c++/7/bits/invoke.h:95 (gdb+0x737e91)
        #9 std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run()::{lambda()#1}::operator()() const /usr/include/c++/7/future:1421 (gdb+0x737b59)
        #10 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++/7/future:1362 (gdb+0x738660)
        #11 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++/7/bits/std_function.h:302 (gdb+0x73825c)
        #12 std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>::operator()() const /usr/include/c++/7/bits/std_function.h:706 (gdb+0x733623)
        #13 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++/7/future:561 (gdb+0x732bdf)
        #14 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++/7/bits/invoke.h:73 (gdb+0x734c4f)
        #15 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++/7/bits/invoke.h:95 (gdb+0x733bc5)
        #16 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++/7/mutex:672 (gdb+0x73300d)
        #17 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()#2}::operator()() const /usr/include/c++/7/mutex:677 (gdb+0x7330b2)
        #18 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()#2}::_FUN() /usr/include/c++/7/mutex:677 (gdb+0x7330f2)
        #19 pthread_once <null> (libtsan.so.0+0x4457c)
        #20 __gthread_once /usr/include/c++/7/x86_64-suse-linux/bits/gthr-default.h:699 (gdb+0x72f5dd)
        #21 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++/7/mutex:684 (gdb+0x733224)
        #22 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++/7/future:401 (gdb+0x732852)
        #23 std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run() /usr/include/c++/7/future:1423 (gdb+0x737bef)
        #24 std::packaged_task<void ()>::operator()() /usr/include/c++/7/future:1556 (gdb+0x1dad25a)
        #25 gdb::thread_pool::thread_function() gdbsupport/thread-pool.cc:242 (gdb+0x1dacb7c)
        #26 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++/7/bits/invoke.h:73 (gdb+0x1dadc2b)
        #27 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++/7/bits/invoke.h:95 (gdb+0x1dad05c)
        #28 decltype (__invoke((_S_declval<0ul>)(), (_S_declval<1ul>)())) std::thread::_Invoker<std::tuple<void (gdb::thread_pool::*)(), gdb::thread_pool*> >::_M_invoke<0ul, 1ul>(std::_Index_tuple<0ul, 1ul>) /usr/include/c++/7/thread:234 (gdb+0x1db038e)
        #29 std::thread::_Invoker<std::tuple<void (gdb::thread_pool::*)(), gdb::thread_pool*> >::operator()() /usr/include/c++/7/thread:243 (gdb+0x1db0319)
        #30 std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (gdb::thread_pool::*)(), gdb::thread_pool*> > >::_M_run() /usr/include/c++/7/thread:186 (gdb+0x1db02ce)
        #31 <null> <null> (libstdc++.so.6+0xdcac2)
      ...
    SUMMARY: ThreadSanitizer: data race gdb/dwarf2/read.c:21513 in dwarf2_per_cu_data::get_header() const
    ...
    
    The race happens when issuing the "file $exec" command.
    
    The race is between:
    - a worker thread writing the index cache, and in the process reading
       dwarf2_per_cu_data::is_debug_type, and
    - the main thread writing to dwarf2_per_cu_data::m_header_read_in.
    
    The two bitfields dwarf2_per_cu_data::m_header_read_in and
    dwarf2_per_cu_data::is_debug_type share the same bitfield container.
    
    Fix this by making dwarf2_per_cu_data::m_header_read_in a packed<bool, 1>.
    
    Tested on x86_64-linux.
    
    Approved-By: Tom Tromey <tom@tromey.com>
    
    PR symtab/30392
    Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=30392
Comment 12 Tom de Vries 2023-08-04 13:10:53 UTC
Fixed.