[binutils-gdb/gdb-17-branch] gdb/dwarf: make dwarf2_per_cu size fields atomic

Simon Marchi simark@sourceware.org
Tue Jan 13 17:29:18 GMT 2026


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

commit 32adc7212e4b32effdb7768250e08050a2f5532c
Author: Simon Marchi <simon.marchi@polymtl.ca>
Date:   Sat Jan 10 22:40:30 2026 -0500

    gdb/dwarf: make dwarf2_per_cu size fields atomic
    
    Make m_addr_size, m_offset_size, and m_ref_addr_size use std::atomic.
    Multiple indexer threads may set these values concurrently, which
    currently causes a TSan failure:
    
         WARNING: ThreadSanitizer: data race (pid=1535364)
           Write of size 1 at 0xfffed1813515 by thread T1:
             #0 dwarf2_per_cu::set_addr_size(unsigned char) /home/vries/gdb/src/gdb/dwarf2/read.h:291 (gdb+0x98af68) (BuildId: cce1d3c72972f5759cd1746e1a001e90d7498301)
             #1 cutu_reader::cutu_reader(dwarf2_per_cu&, dwarf2_per_objfile&, abbrev_table const*, dwarf2_cu*, bool, language, abbrev_table_cache const*) /home/vries/gdb/src/gdb/dwarf2/read.c:3114 (gdb+0x9472b4) (BuildId: cce1d3c72972f5759cd1746e1a001e90d7498301)
             #2 std::__detail::_MakeUniq<cutu_reader>::__single_object std::make_unique<cutu_reader, dwarf2_per_cu&, dwarf2_per_objfile&, decltype(nullptr), decltype(nullptr), bool, language, abbrev_table_cache const*>(dwarf2_per_cu&, dwarf2_per_objfile&, decltype(nullptr)&&, decltype(nullptr)&&, bool&&, language&&, abbrev_table_cache const*&&) /usr/include/c++/15/bits/unique_ptr.h:1084 (gdb+0x891f98) (BuildId: cce1d3c72972f5759cd1746e1a001e90d7498301)
             #3 cooked_indexer::ensure_cu_exists(cutu_reader*, section_and_offset const&, bool) /home/vries/gdb/src/gdb/dwarf2/cooked-indexer.c:118 (gdb+0x88e1e8) (BuildId: cce1d3c72972f5759cd1746e1a001e90d7498301)
             #4 cooked_indexer::scan_attributes(dwarf2_per_cu*, cutu_reader*, unsigned char const*, unsigned char const*, abbrev_info const*, char const**, char const**, enum_flags<cooked_index_flag_enum>*, sect_offset*, cooked_index_entry const**, parent_map::addr_type*, bool*, bool) /home/vries/gdb/src/gdb/dwarf2/cooked-indexer.c:316 (gdb+0x88ed1c) (BuildId: cce1d3c72972f5759cd1746e1a001e90d7498301)
             #5 cooked_indexer::index_dies(cutu_reader*, unsigned char const*, std::variant<cooked_index_entry const*, parent_map::addr_type>, bool) /home/vries/gdb/src/gdb/dwarf2/cooked-indexer.c:539 (gdb+0x88fa50) (BuildId: cce1d3c72972f5759cd1746e1a001e90d7498301)
             #6 cooked_indexer::make_index(cutu_reader*) /home/vries/gdb/src/gdb/dwarf2/cooked-indexer.c:718 (gdb+0x890430) (BuildId: cce1d3c72972f5759cd1746e1a001e90d7498301)
             ...
    
          Previous write of size 1 at 0xfffed1813515 by thread T4:
            #0 dwarf2_per_cu::set_addr_size(unsigned char) /home/vries/gdb/src/gdb/dwarf2/read.h:291 (gdb+0x98af68) (BuildId: cce1d3c72972f5759cd1746e1a001e90d7498301)
            #1 cutu_reader::cutu_reader(dwarf2_per_cu&, dwarf2_per_objfile&, abbrev_table const*, dwarf2_cu*, bool, language, abbrev_table_cache const*) /home/vries/gdb/src/gdb/dwarf2/read.c:3114 (gdb+0x9472b4) (BuildId: cce1d3c72972f5759cd1746e1a001e90d7498301)
            #2 std::__detail::_MakeUniq<cutu_reader>::__single_object std::make_unique<cutu_reader, dwarf2_per_cu&, dwarf2_per_objfile&, decltype(nullptr), decltype(nullptr), bool, language, abbrev_table_cache const*>(dwarf2_per_cu&, dwarf2_per_objfile&, decltype(nullptr)&&, decltype(nullptr)&&, bool&&, language&&, abbrev_table_cache const*&&) /usr/include/c++/15/bits/unique_ptr.h:1084 (gdb+0x891f98) (BuildId: cce1d3c72972f5759cd1746e1a001e90d7498301)
            #3 cooked_indexer::ensure_cu_exists(cutu_reader*, section_and_offset const&, bool) /home/vries/gdb/src/gdb/dwarf2/cooked-indexer.c:118 (gdb+0x88e1e8) (BuildId: cce1d3c72972f5759cd1746e1a001e90d7498301)
            #4 cooked_indexer::index_imported_unit(cutu_reader*, unsigned char const*, abbrev_info const*) /home/vries/gdb/src/gdb/dwarf2/cooked-indexer.c:431 (gdb+0x88f454) (BuildId: cce1d3c72972f5759cd1746e1a001e90d7498301)
            #5 cooked_indexer::index_dies(cutu_reader*, unsigned char const*, std::variant<cooked_index_entry const*, parent_map::addr_type>, bool) /home/vries/gdb/src/gdb/dwarf2/cooked-indexer.c:498 (gdb+0x88f770) (BuildId: cce1d3c72972f5759cd1746e1a001e90d7498301)
            #6 cooked_indexer::index_imported_unit(cutu_reader*, unsigned char const*, abbrev_info const*) /home/vries/gdb/src/gdb/dwarf2/cooked-indexer.c:434 (gdb+0x88f4ac) (BuildId: cce1d3c72972f5759cd1746e1a001e90d7498301)
            #7 cooked_indexer::index_dies(cutu_reader*, unsigned char const*, std::variant<cooked_index_entry const*, parent_map::addr_type>, bool) /home/vries/gdb/src/gdb/dwarf2/cooked-indexer.c:498 (gdb+0x88f770) (BuildId: cce1d3c72972f5759cd1746e1a001e90d7498301)
            #8 cooked_indexer::make_index(cutu_reader*) /home/vries/gdb/src/gdb/dwarf2/cooked-indexer.c:718 (gdb+0x890430) (BuildId: cce1d3c72972f5759cd1746e1a001e90d7498301)
            ...
    
    It's fine for multiple threads to try to set these values concurrently.
    The only condition is that either the previous value was 0 (unset) or
    equals the new value being set.
    
    Change-Id: Ib13218707cefdf33a51b3246ba5773a7800463b9
    Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=33775
    Reviewed-By: Tom de Vries <tdevries@suse.de>
    (cherry picked from commit 10dc500696f6625b3dcc70560e7762c9a9b01391)

Diff:
---
 gdb/dwarf2/read.h | 23 ++++++++++++++++-------
 1 file changed, 16 insertions(+), 7 deletions(-)

diff --git a/gdb/dwarf2/read.h b/gdb/dwarf2/read.h
index f10375bc980..2d68586f0bc 100644
--- a/gdb/dwarf2/read.h
+++ b/gdb/dwarf2/read.h
@@ -224,9 +224,9 @@ public:
 private:
   /* Sizes for an address, an offset, and a section offset.  These fields are
      set by cutu_reader when the unit is read.  */
-  std::uint8_t m_addr_size = 0;
-  std::uint8_t m_offset_size = 0;
-  std::uint8_t m_ref_addr_size = 0;
+  std::atomic<std::uint8_t> m_addr_size = 0;
+  std::atomic<std::uint8_t> m_offset_size = 0;
+  std::atomic<std::uint8_t> m_ref_addr_size = 0;
 
 public:
   /* Our index in the unshared "symtabs" vector.  */
@@ -285,7 +285,10 @@ public:
   /* Set the address size given in the compilation unit header for
      this CU.  */
   void set_addr_size (std::uint8_t addr_size)
-  { m_addr_size = addr_size; }
+  {
+    std::uint8_t old = m_addr_size.exchange (addr_size);
+    gdb_assert (old == 0 || old == addr_size);
+  }
 
   /* Return the offset size given in the compilation unit header for
      this CU.  */
@@ -298,7 +301,10 @@ public:
   /* Set the offset size given in the compilation unit header for
      this CU.  */
   void set_offset_size (std::uint8_t offset_size)
-  { m_offset_size = offset_size; }
+  {
+    std::uint8_t old = m_offset_size.exchange (offset_size);
+    gdb_assert (old == 0 || old == offset_size);
+  }
 
   /* Return the DW_FORM_ref_addr size given in the compilation unit
      header for this CU.  */
@@ -308,10 +314,13 @@ public:
     return m_ref_addr_size;
   }
 
-  /* Return the DW_FORM_ref_addr size given in the compilation unit
+  /* Set the DW_FORM_ref_addr size given in the compilation unit
      header for this CU.  */
   void set_ref_addr_size (std::uint8_t ref_addr_size)
-  { m_ref_addr_size = ref_addr_size; }
+  {
+    std::uint8_t old = m_ref_addr_size.exchange (ref_addr_size);
+    gdb_assert (old == 0 || old == ref_addr_size);
+  }
 
   /* Return length of this CU.  */
   unsigned int length () const


More information about the Gdb-cvs mailing list