]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
gdb/dwarf: make dwarf2_per_cu size fields atomic
authorSimon Marchi <simon.marchi@polymtl.ca>
Sun, 11 Jan 2026 03:40:30 +0000 (22:40 -0500)
committerSimon Marchi <simon.marchi@polymtl.ca>
Mon, 12 Jan 2026 18:37:25 +0000 (13:37 -0500)
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>
gdb/dwarf2/read.h

index 4e89f0ed1fc8a03ee3ef24b94123d9e9b4cae533..112bf7b7800792f788aff538208c8e4454abc856 100644 (file)
@@ -229,9 +229,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.  */
@@ -311,7 +311,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.  */
@@ -324,7 +327,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.  */
@@ -334,10 +340,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