[llvm] [DebugInfo/DWARF] Fix data race in DWARFUnit DIE extraction (PR #180470)

Shivam Kunwar via llvm-commits llvm-commits at lists.llvm.org
Sun Feb 8 22:49:01 PST 2026


https://github.com/phyBrackets updated https://github.com/llvm/llvm-project/pull/180470

>From c427ce0df0343333b1734dc190622e8b7276d027 Mon Sep 17 00:00:00 2001
From: Shivam Kunwar <shivam.kunwar at kdab.com>
Date: Mon, 9 Feb 2026 11:16:12 +0530
Subject: [PATCH] [DebugInfo/DWARF] Fix data race in DWARFUnit DIE extraction

---
 llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h |  9 ++++--
 llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp        | 30 ++++++++++++++-----
 2 files changed, 29 insertions(+), 10 deletions(-)

diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h
index bd204f626ac01..292adb7675a4c 100644
--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h
@@ -23,6 +23,7 @@
 #include "llvm/DebugInfo/DWARF/DWARFUnitIndex.h"
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/DataExtractor.h"
+#include "llvm/Support/RWMutex.h"
 #include <cassert>
 #include <cstddef>
 #include <cstdint>
@@ -246,7 +247,9 @@ class LLVM_ABI DWARFUnit {
 
   mutable const DWARFAbbreviationDeclarationSet *Abbrevs;
   std::optional<object::SectionedAddress> BaseAddr;
+
   /// The compile unit debug information entry items.
+  mutable sys::RWMutex DieArrayMutex;
   std::vector<DWARFDebugInfoEntry> DieArray;
 
   /// Map from range's start address to end address and corresponding DIE.
@@ -538,9 +541,10 @@ class LLVM_ABI DWARFUnit {
   /// Return the DIE object for a given offset \p Offset inside the
   /// unit's DIE vector.
   DWARFDie getDIEForOffset(uint64_t Offset) {
-    if (std::optional<uint32_t> DieIdx = getDIEIndexForOffset(Offset))
+    if (std::optional<uint32_t> DieIdx = getDIEIndexForOffset(Offset)) {
+      sys::ScopedReader ReadLock(DieArrayMutex);
       return DWARFDie(this, &DieArray[*DieIdx]);
-
+    }
     return DWARFDie();
   }
 
@@ -548,6 +552,7 @@ class LLVM_ABI DWARFUnit {
   /// unit's DIE vector.
   std::optional<uint32_t> getDIEIndexForOffset(uint64_t Offset) {
     extractDIEsIfNeeded(false);
+    sys::ScopedReader ReadLock(DieArrayMutex);
     auto It =
         llvm::partition_point(DieArray, [=](const DWARFDebugInfoEntry &DIE) {
           return DIE.getOffset() < Offset;
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
index b8fbdfc8c1d70..e9bd986b80bc5 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
@@ -504,17 +504,30 @@ void DWARFUnit::extractDIEsIfNeeded(bool CUDieOnly) {
 }
 
 Error DWARFUnit::tryExtractDIEsIfNeeded(bool CUDieOnly) {
-  if ((CUDieOnly && !DieArray.empty()) || DieArray.size() > 1)
-    return Error::success(); // Already parsed.
+  bool DoPostExtractInit = false;
 
-  bool HasCUDie = !DieArray.empty();
-  extractDIEsToVector(!HasCUDie, !CUDieOnly, DieArray);
+  {
+    sys::ScopedReader ReadLock(DieArrayMutex);
+    if ((CUDieOnly && !DieArray.empty()) || DieArray.size() > 1)
+      return Error::success(); // Already parsed.
+  }
 
-  if (DieArray.empty())
-    return Error::success();
+  {
+    sys::ScopedWriter WriteLock(DieArrayMutex);
+    if ((CUDieOnly && !DieArray.empty()) || DieArray.size() > 1)
+      return Error::success(); // Another thread parsed while we waited
+
+    bool HasCUDie = !DieArray.empty();
+    extractDIEsToVector(!HasCUDie, !CUDieOnly, DieArray);
+
+    if (DieArray.empty())
+      return Error::success();
+
+    // Only do post-init if we just parsed the CU DIE for the first time
+    DoPostExtractInit = !HasCUDie;
+  }
 
-  // If CU DIE was just parsed, copy several attribute values from it.
-  if (HasCUDie)
+  if (!DoPostExtractInit)
     return Error::success();
 
   DWARFDie UnitDie(this, &DieArray[0]);
@@ -660,6 +673,7 @@ bool DWARFUnit::parseDWO(StringRef DWOAlternativeLocation) {
 }
 
 void DWARFUnit::clearDIEs(bool KeepCUDie) {
+  sys::ScopedWriter WriteLock(DieArrayMutex);
   // Do not use resize() + shrink_to_fit() to free memory occupied by dies.
   // shrink_to_fit() is a *non-binding* request to reduce capacity() to size().
   // It depends on the implementation whether the request is fulfilled.



More information about the llvm-commits mailing list