From: Simon Marchi Date: Sun, 11 Jan 2026 03:40:30 +0000 (-0500) Subject: gdb/dwarf: make dwarf2_per_cu size fields atomic X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=10dc500696f6625b3dcc70560e7762c9a9b01391;p=thirdparty%2Fbinutils-gdb.git 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::__single_object std::make_unique(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*, 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, 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::__single_object std::make_unique(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, 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, 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 --- diff --git a/gdb/dwarf2/read.h b/gdb/dwarf2/read.h index 4e89f0ed1fc..112bf7b7800 100644 --- a/gdb/dwarf2/read.h +++ b/gdb/dwarf2/read.h @@ -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 m_addr_size = 0; + std::atomic m_offset_size = 0; + std::atomic 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