[Lldb-commits] [lldb] [lldb] Make TypeSystem::m_sym_file atomic to fix data race (PR #198923)

via lldb-commits lldb-commits at lists.llvm.org
Wed May 20 15:48:51 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-lldb

Author: Jonas Devlieghere (JDevlieghere)

<details>
<summary>Changes</summary>

SymbolFileCommon::GetTypeSystemForLanguage unconditionally writes this pointer with `ts->SetSymbolFile(this)` on every lookup, which races with concurrent reads from other threads.

The race is benign in practice: there is exactly (one SymbolFile per Module, so every writer stores the same pointer) but it is still undefined behavior under the C++ memory model.

Make the field std::atomic<SymbolFile *> and turn SetSymbolFile into a compare-exchange that asserts a TypeSystem is never rebound to a different SymbolFile, documenting the invariant that lets us get away with this.

The alternative is to have the SymbolFile pointer passed in through the constructor, but that would require updating a bunch of call sites, including various plugin interfaces.

Found by ThreadSanitizer as part of #<!-- -->197792.

---
Full diff: https://github.com/llvm/llvm-project/pull/198923.diff


1 Files Affected:

- (modified) lldb/include/lldb/Symbol/TypeSystem.h (+27-5) 


``````````diff
diff --git a/lldb/include/lldb/Symbol/TypeSystem.h b/lldb/include/lldb/Symbol/TypeSystem.h
index ee5a27b157490..6899d71688431 100644
--- a/lldb/include/lldb/Symbol/TypeSystem.h
+++ b/lldb/include/lldb/Symbol/TypeSystem.h
@@ -9,6 +9,8 @@
 #ifndef LLDB_SYMBOL_TYPESYSTEM_H
 #define LLDB_SYMBOL_TYPESYSTEM_H
 
+#include <atomic>
+#include <cassert>
 #include <functional>
 #include <mutex>
 #include <optional>
@@ -91,10 +93,6 @@ class TypeSystem : public PluginInterface,
   virtual PDBASTParser *GetPDBParser() { return nullptr; }
   virtual npdb::PdbAstBuilder *GetNativePDBParser() { return nullptr; }
 
-  virtual SymbolFile *GetSymbolFile() const { return m_sym_file; }
-
-  virtual void SetSymbolFile(SymbolFile *sym_file) { m_sym_file = sym_file; }
-
   // CompilerDecl functions
   virtual ConstString DeclGetName(void *opaque_decl) = 0;
 
@@ -559,13 +557,37 @@ class TypeSystem : public PluginInterface,
 
   virtual std::optional<llvm::json::Value> ReportStatistics();
 
+  SymbolFile *GetSymbolFile() const { return m_sym_file.load(); }
+
+  /// Bind this TypeSystem to its owning SymbolFile.
+  ///
+  /// A TypeSystem is created by its Module's TypeSystemMap before that
+  /// Module has an associated SymbolFile. The SymbolFile installs this
+  /// back-pointer when it first hands out the TypeSystem so that lazy
+  /// type-completion callbacks can route through it.
+  ///
+  /// Each Module owns at most one SymbolFile and one TypeSystem per
+  /// language, so the binding is expected to be established exactly once.
+  /// Repeated calls with the same pointer are no-ops. Rebinding to a
+  /// different non-null SymbolFile is a programming error.
+  void SetSymbolFile(SymbolFile *sym_file) {
+    SymbolFile *expected = nullptr;
+    if (m_sym_file.compare_exchange_strong(expected, sym_file))
+      return;
+    assert(expected == sym_file &&
+           "TypeSystem rebound to a different SymbolFile");
+  }
+
   bool GetHasForcefullyCompletedTypes() const {
     return m_has_forcefully_completed_types;
   }
+
 protected:
-  SymbolFile *m_sym_file = nullptr;
   /// Used for reporting statistics.
   bool m_has_forcefully_completed_types = false;
+
+private:
+  std::atomic<SymbolFile *> m_sym_file = nullptr;
 };
 
 class TypeSystemMap {

``````````

</details>


https://github.com/llvm/llvm-project/pull/198923


More information about the lldb-commits mailing list