public inbox for gdb-prs@sourceware.org
help / color / mirror / Atom feed
* [Bug symtab/30392] New: [gdb/symtab] thread sanitizer data race in gdb.base/index-cache.exp
@ 2023-04-26 17:34 vries at gcc dot gnu.org
  2023-04-26 17:35 ` [Bug symtab/30392] " vries at gcc dot gnu.org
                   ` (13 more replies)
  0 siblings, 14 replies; 15+ messages in thread
From: vries at gcc dot gnu.org @ 2023-04-26 17:34 UTC (permalink / raw)
  To: gdb-prs

https://sourceware.org/bugzilla/show_bug.cgi?id=30392

            Bug ID: 30392
           Summary: [gdb/symtab] thread sanitizer data race in
                    gdb.base/index-cache.exp
           Product: gdb
           Version: HEAD
            Status: NEW
          Severity: normal
          Priority: P2
         Component: symtab
          Assignee: unassigned at sourceware dot org
          Reporter: vries at gcc dot gnu.org
  Target Milestone: ---

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
...

-- 
You are receiving this mail because:
You are on the CC list for the bug.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [Bug symtab/30392] [gdb/symtab] thread sanitizer data race in gdb.base/index-cache.exp
  2023-04-26 17:34 [Bug symtab/30392] New: [gdb/symtab] thread sanitizer data race in gdb.base/index-cache.exp vries at gcc dot gnu.org
@ 2023-04-26 17:35 ` vries at gcc dot gnu.org
  2023-04-26 17:35 ` vries at gcc dot gnu.org
                   ` (12 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: vries at gcc dot gnu.org @ 2023-04-26 17:35 UTC (permalink / raw)
  To: gdb-prs

https://sourceware.org/bugzilla/show_bug.cgi?id=30392

--- Comment #1 from Tom de Vries <vries at gcc dot gnu.org> ---
Created attachment 14852
  --> https://sourceware.org/bugzilla/attachment.cgi?id=14852&action=edit
offending gdb.log

-- 
You are receiving this mail because:
You are on the CC list for the bug.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [Bug symtab/30392] [gdb/symtab] thread sanitizer data race in gdb.base/index-cache.exp
  2023-04-26 17:34 [Bug symtab/30392] New: [gdb/symtab] thread sanitizer data race in gdb.base/index-cache.exp vries at gcc dot gnu.org
  2023-04-26 17:35 ` [Bug symtab/30392] " vries at gcc dot gnu.org
@ 2023-04-26 17:35 ` vries at gcc dot gnu.org
  2023-04-26 20:09 ` vries at gcc dot gnu.org
                   ` (11 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: vries at gcc dot gnu.org @ 2023-04-26 17:35 UTC (permalink / raw)
  To: gdb-prs

https://sourceware.org/bugzilla/show_bug.cgi?id=30392

Tom de Vries <vries at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |simark at simark dot ca

-- 
You are receiving this mail because:
You are on the CC list for the bug.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [Bug symtab/30392] [gdb/symtab] thread sanitizer data race in gdb.base/index-cache.exp
  2023-04-26 17:34 [Bug symtab/30392] New: [gdb/symtab] thread sanitizer data race in gdb.base/index-cache.exp vries at gcc dot gnu.org
  2023-04-26 17:35 ` [Bug symtab/30392] " vries at gcc dot gnu.org
  2023-04-26 17:35 ` vries at gcc dot gnu.org
@ 2023-04-26 20:09 ` vries at gcc dot gnu.org
  2023-04-27 23:27 ` tromey at sourceware dot org
                   ` (10 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: vries at gcc dot gnu.org @ 2023-04-26 20:09 UTC (permalink / raw)
  To: gdb-prs

https://sourceware.org/bugzilla/show_bug.cgi?id=30392

Tom de Vries <vries at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |tromey at sourceware dot org

-- 
You are receiving this mail because:
You are on the CC list for the bug.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [Bug symtab/30392] [gdb/symtab] thread sanitizer data race in gdb.base/index-cache.exp
  2023-04-26 17:34 [Bug symtab/30392] New: [gdb/symtab] thread sanitizer data race in gdb.base/index-cache.exp vries at gcc dot gnu.org
                   ` (2 preceding siblings ...)
  2023-04-26 20:09 ` vries at gcc dot gnu.org
@ 2023-04-27 23:27 ` tromey at sourceware dot org
  2023-04-28 14:30 ` simon.marchi at polymtl dot ca
                   ` (9 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: tromey at sourceware dot org @ 2023-04-27 23:27 UTC (permalink / raw)
  To: gdb-prs

https://sourceware.org/bugzilla/show_bug.cgi?id=30392

--- Comment #2 from Tom Tromey <tromey at sourceware dot org> ---
The reader probably should capture the necessarily globals
on the main thread and stash them until the index has been
written.

-- 
You are receiving this mail because:
You are on the CC list for the bug.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [Bug symtab/30392] [gdb/symtab] thread sanitizer data race in gdb.base/index-cache.exp
  2023-04-26 17:34 [Bug symtab/30392] New: [gdb/symtab] thread sanitizer data race in gdb.base/index-cache.exp vries at gcc dot gnu.org
                   ` (3 preceding siblings ...)
  2023-04-27 23:27 ` tromey at sourceware dot org
@ 2023-04-28 14:30 ` simon.marchi at polymtl dot ca
  2023-07-25 12:27 ` vries at gcc dot gnu.org
                   ` (8 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: simon.marchi at polymtl dot ca @ 2023-04-28 14:30 UTC (permalink / raw)
  To: gdb-prs

https://sourceware.org/bugzilla/show_bug.cgi?id=30392

Simon Marchi <simon.marchi at polymtl dot ca> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |simon.marchi at polymtl dot ca

--- Comment #3 from Simon Marchi <simon.marchi at polymtl dot ca> ---
(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.

-- 
You are receiving this mail because:
You are on the CC list for the bug.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [Bug symtab/30392] [gdb/symtab] thread sanitizer data race in gdb.base/index-cache.exp
  2023-04-26 17:34 [Bug symtab/30392] New: [gdb/symtab] thread sanitizer data race in gdb.base/index-cache.exp vries at gcc dot gnu.org
                   ` (4 preceding siblings ...)
  2023-04-28 14:30 ` simon.marchi at polymtl dot ca
@ 2023-07-25 12:27 ` vries at gcc dot gnu.org
  2023-07-28  8:58 ` vries at gcc dot gnu.org
                   ` (7 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: vries at gcc dot gnu.org @ 2023-07-25 12:27 UTC (permalink / raw)
  To: gdb-prs

https://sourceware.org/bugzilla/show_bug.cgi?id=30392

--- Comment #4 from Tom de Vries <vries at gcc dot gnu.org> ---
(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.

-- 
You are receiving this mail because:
You are on the CC list for the bug.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [Bug symtab/30392] [gdb/symtab] thread sanitizer data race in gdb.base/index-cache.exp
  2023-04-26 17:34 [Bug symtab/30392] New: [gdb/symtab] thread sanitizer data race in gdb.base/index-cache.exp vries at gcc dot gnu.org
                   ` (5 preceding siblings ...)
  2023-07-25 12:27 ` vries at gcc dot gnu.org
@ 2023-07-28  8:58 ` vries at gcc dot gnu.org
  2023-07-28  9:32 ` vries at gcc dot gnu.org
                   ` (6 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: vries at gcc dot gnu.org @ 2023-07-28  8:58 UTC (permalink / raw)
  To: gdb-prs

https://sourceware.org/bugzilla/show_bug.cgi?id=30392

--- Comment #5 from Tom de Vries <vries at gcc dot gnu.org> ---
Posted an RFC (
https://sourceware.org/pipermail/gdb-patches/2023-July/201189.html ).

-- 
You are receiving this mail because:
You are on the CC list for the bug.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [Bug symtab/30392] [gdb/symtab] thread sanitizer data race in gdb.base/index-cache.exp
  2023-04-26 17:34 [Bug symtab/30392] New: [gdb/symtab] thread sanitizer data race in gdb.base/index-cache.exp vries at gcc dot gnu.org
                   ` (6 preceding siblings ...)
  2023-07-28  8:58 ` vries at gcc dot gnu.org
@ 2023-07-28  9:32 ` vries at gcc dot gnu.org
  2023-07-28  9:36 ` vries at gcc dot gnu.org
                   ` (5 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: vries at gcc dot gnu.org @ 2023-07-28  9:32 UTC (permalink / raw)
  To: gdb-prs

https://sourceware.org/bugzilla/show_bug.cgi?id=30392

--- Comment #6 from Tom de Vries <vries at gcc dot gnu.org> ---
(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.

-- 
You are receiving this mail because:
You are on the CC list for the bug.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [Bug symtab/30392] [gdb/symtab] thread sanitizer data race in gdb.base/index-cache.exp
  2023-04-26 17:34 [Bug symtab/30392] New: [gdb/symtab] thread sanitizer data race in gdb.base/index-cache.exp vries at gcc dot gnu.org
                   ` (7 preceding siblings ...)
  2023-07-28  9:32 ` vries at gcc dot gnu.org
@ 2023-07-28  9:36 ` vries at gcc dot gnu.org
  2023-08-04 13:03 ` cvs-commit at gcc dot gnu.org
                   ` (4 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: vries at gcc dot gnu.org @ 2023-07-28  9:36 UTC (permalink / raw)
  To: gdb-prs

https://sourceware.org/bugzilla/show_bug.cgi?id=30392

--- Comment #7 from Tom de Vries <vries at gcc dot gnu.org> ---
(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.

-- 
You are receiving this mail because:
You are on the CC list for the bug.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [Bug symtab/30392] [gdb/symtab] thread sanitizer data race in gdb.base/index-cache.exp
  2023-04-26 17:34 [Bug symtab/30392] New: [gdb/symtab] thread sanitizer data race in gdb.base/index-cache.exp vries at gcc dot gnu.org
                   ` (8 preceding siblings ...)
  2023-07-28  9:36 ` vries at gcc dot gnu.org
@ 2023-08-04 13:03 ` cvs-commit at gcc dot gnu.org
  2023-08-04 13:03 ` cvs-commit at gcc dot gnu.org
                   ` (3 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: cvs-commit at gcc dot gnu.org @ 2023-08-04 13:03 UTC (permalink / raw)
  To: gdb-prs

https://sourceware.org/bugzilla/show_bug.cgi?id=30392

--- Comment #8 from cvs-commit at gcc dot gnu.org <cvs-commit at gcc dot gnu.org> ---
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

-- 
You are receiving this mail because:
You are on the CC list for the bug.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [Bug symtab/30392] [gdb/symtab] thread sanitizer data race in gdb.base/index-cache.exp
  2023-04-26 17:34 [Bug symtab/30392] New: [gdb/symtab] thread sanitizer data race in gdb.base/index-cache.exp vries at gcc dot gnu.org
                   ` (9 preceding siblings ...)
  2023-08-04 13:03 ` cvs-commit at gcc dot gnu.org
@ 2023-08-04 13:03 ` cvs-commit at gcc dot gnu.org
  2023-08-04 13:03 ` cvs-commit at gcc dot gnu.org
                   ` (2 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: cvs-commit at gcc dot gnu.org @ 2023-08-04 13:03 UTC (permalink / raw)
  To: gdb-prs

https://sourceware.org/bugzilla/show_bug.cgi?id=30392

--- Comment #9 from cvs-commit at gcc dot gnu.org <cvs-commit at gcc dot gnu.org> ---
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

-- 
You are receiving this mail because:
You are on the CC list for the bug.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [Bug symtab/30392] [gdb/symtab] thread sanitizer data race in gdb.base/index-cache.exp
  2023-04-26 17:34 [Bug symtab/30392] New: [gdb/symtab] thread sanitizer data race in gdb.base/index-cache.exp vries at gcc dot gnu.org
                   ` (10 preceding siblings ...)
  2023-08-04 13:03 ` cvs-commit at gcc dot gnu.org
@ 2023-08-04 13:03 ` cvs-commit at gcc dot gnu.org
  2023-08-04 13:03 ` cvs-commit at gcc dot gnu.org
  2023-08-04 13:10 ` vries at gcc dot gnu.org
  13 siblings, 0 replies; 15+ messages in thread
From: cvs-commit at gcc dot gnu.org @ 2023-08-04 13:03 UTC (permalink / raw)
  To: gdb-prs

https://sourceware.org/bugzilla/show_bug.cgi?id=30392

--- Comment #10 from cvs-commit at gcc dot gnu.org <cvs-commit at gcc dot gnu.org> ---
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

-- 
You are receiving this mail because:
You are on the CC list for the bug.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [Bug symtab/30392] [gdb/symtab] thread sanitizer data race in gdb.base/index-cache.exp
  2023-04-26 17:34 [Bug symtab/30392] New: [gdb/symtab] thread sanitizer data race in gdb.base/index-cache.exp vries at gcc dot gnu.org
                   ` (11 preceding siblings ...)
  2023-08-04 13:03 ` cvs-commit at gcc dot gnu.org
@ 2023-08-04 13:03 ` cvs-commit at gcc dot gnu.org
  2023-08-04 13:10 ` vries at gcc dot gnu.org
  13 siblings, 0 replies; 15+ messages in thread
From: cvs-commit at gcc dot gnu.org @ 2023-08-04 13:03 UTC (permalink / raw)
  To: gdb-prs

https://sourceware.org/bugzilla/show_bug.cgi?id=30392

--- Comment #11 from cvs-commit at gcc dot gnu.org <cvs-commit at gcc dot gnu.org> ---
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

-- 
You are receiving this mail because:
You are on the CC list for the bug.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [Bug symtab/30392] [gdb/symtab] thread sanitizer data race in gdb.base/index-cache.exp
  2023-04-26 17:34 [Bug symtab/30392] New: [gdb/symtab] thread sanitizer data race in gdb.base/index-cache.exp vries at gcc dot gnu.org
                   ` (12 preceding siblings ...)
  2023-08-04 13:03 ` cvs-commit at gcc dot gnu.org
@ 2023-08-04 13:10 ` vries at gcc dot gnu.org
  13 siblings, 0 replies; 15+ messages in thread
From: vries at gcc dot gnu.org @ 2023-08-04 13:10 UTC (permalink / raw)
  To: gdb-prs

https://sourceware.org/bugzilla/show_bug.cgi?id=30392

Tom de Vries <vries at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|NEW                         |RESOLVED
   Target Milestone|---                         |14.1
         Resolution|---                         |FIXED

--- Comment #12 from Tom de Vries <vries at gcc dot gnu.org> ---
Fixed.

-- 
You are receiving this mail because:
You are on the CC list for the bug.

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2023-08-04 13:10 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-04-26 17:34 [Bug symtab/30392] New: [gdb/symtab] thread sanitizer data race in gdb.base/index-cache.exp vries at gcc dot gnu.org
2023-04-26 17:35 ` [Bug symtab/30392] " vries at gcc dot gnu.org
2023-04-26 17:35 ` vries at gcc dot gnu.org
2023-04-26 20:09 ` vries at gcc dot gnu.org
2023-04-27 23:27 ` tromey at sourceware dot org
2023-04-28 14:30 ` simon.marchi at polymtl dot ca
2023-07-25 12:27 ` vries at gcc dot gnu.org
2023-07-28  8:58 ` vries at gcc dot gnu.org
2023-07-28  9:32 ` vries at gcc dot gnu.org
2023-07-28  9:36 ` vries at gcc dot gnu.org
2023-08-04 13:03 ` cvs-commit at gcc dot gnu.org
2023-08-04 13:03 ` cvs-commit at gcc dot gnu.org
2023-08-04 13:03 ` cvs-commit at gcc dot gnu.org
2023-08-04 13:03 ` cvs-commit at gcc dot gnu.org
2023-08-04 13:10 ` vries at gcc dot gnu.org

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).