[llvm] 499b69c - [DWARFLinker] Fix data race on the per-unit file-name cache (#208967)

via llvm-commits llvm-commits at lists.llvm.org
Fri Jul 17 07:48:18 PDT 2026


Author: Jonas Devlieghere
Date: 2026-07-17T09:48:12-05:00
New Revision: 499b69cf07e03a23a420ee773261fcfcfc1c3df9

URL: https://github.com/llvm/llvm-project/commit/499b69cf07e03a23a420ee773261fcfcfc1c3df9
DIFF: https://github.com/llvm/llvm-project/commit/499b69cf07e03a23a420ee773261fcfcfc1c3df9.diff

LOG: [DWARFLinker] Fix data race on the per-unit file-name cache (#208967)

CompileUnit::getDirAndFilenameFromLineTable reads and mutates the unit's
FileNames DenseMap without synchronization. During the parallel
type-name assignment phase a unit's cache is touched both by its own
worker and, through cross-unit type-name references
(addReferencedODRDies calling addDieNameFromDeclFileAndDeclLine) by
other units' workers.

The concurrent find/insert/grow corrupts the map and trips the
assertion:

```
Assertion failed: (TheBucket), function findBucketForInsertion, DenseMap.h
```

Guard the cache with a mutex. Store each entry in a heap-allocated pair
so the StringRefs handed back to callers stay valid across a concurrent
rehash. Otherwise a short (small-string-optimized) file name would move
when another insertion grows the map, dangling a StringRef already
returned.

Added: 
    

Modified: 
    llvm/lib/DWARFLinker/Parallel/DWARFLinkerCompileUnit.cpp
    llvm/lib/DWARFLinker/Parallel/DWARFLinkerUnit.h

Removed: 
    


################################################################################
diff  --git a/llvm/lib/DWARFLinker/Parallel/DWARFLinkerCompileUnit.cpp b/llvm/lib/DWARFLinker/Parallel/DWARFLinkerCompileUnit.cpp
index d6fcb557da0f4..5e377d70ea2c8 100644
--- a/llvm/lib/DWARFLinker/Parallel/DWARFLinkerCompileUnit.cpp
+++ b/llvm/lib/DWARFLinker/Parallel/DWARFLinkerCompileUnit.cpp
@@ -1839,10 +1839,11 @@ CompileUnit::getDirAndFilenameFromLineTable(
 
 std::optional<std::pair<StringRef, StringRef>>
 CompileUnit::getDirAndFilenameFromLineTable(uint64_t FileIdx) {
+  std::lock_guard<std::mutex> Guard(FileNamesMutex);
   FileNamesCache::iterator FileData = FileNames.find(FileIdx);
   if (FileData != FileNames.end())
-    return std::make_pair(StringRef(FileData->second.first),
-                          StringRef(FileData->second.second));
+    return {{StringRef(FileData->second->first),
+             StringRef(FileData->second->second)}};
 
   if (const DWARFDebugLine::LineTable *LineTable =
           getOrigUnit().getContext().getLineTableForUnit(&getOrigUnit())) {
@@ -1861,12 +1862,12 @@ CompileUnit::getDirAndFilenameFromLineTable(uint64_t FileIdx) {
       if (isPathAbsoluteOnWindowsOrPosix(FileName)) {
         FileNamesCache::iterator FileData =
             FileNames
-                .insert(std::make_pair(
-                    FileIdx,
-                    std::make_pair(std::string(""), std::move(FileName))))
+                .insert({FileIdx,
+                         std::make_unique<std::pair<std::string, std::string>>(
+                             std::string(""), std::move(FileName))})
                 .first;
-        return std::make_pair(StringRef(FileData->second.first),
-                              StringRef(FileData->second.second));
+        return {{StringRef(FileData->second->first),
+                 StringRef(FileData->second->second)}};
       }
 
       SmallString<256> FilePath;
@@ -1912,12 +1913,12 @@ CompileUnit::getDirAndFilenameFromLineTable(uint64_t FileIdx) {
 
       FileNamesCache::iterator FileData =
           FileNames
-              .insert(
-                  std::make_pair(FileIdx, std::make_pair(std::string(FilePath),
-                                                         std::move(FileName))))
+              .insert({FileIdx,
+                       std::make_unique<std::pair<std::string, std::string>>(
+                           std::string(FilePath), std::move(FileName))})
               .first;
-      return std::make_pair(StringRef(FileData->second.first),
-                            StringRef(FileData->second.second));
+      return {{StringRef(FileData->second->first),
+               StringRef(FileData->second->second)}};
     }
   }
 

diff  --git a/llvm/lib/DWARFLinker/Parallel/DWARFLinkerUnit.h b/llvm/lib/DWARFLinker/Parallel/DWARFLinkerUnit.h
index 18e14495d9645..2bb990593b56a 100644
--- a/llvm/lib/DWARFLinker/Parallel/DWARFLinkerUnit.h
+++ b/llvm/lib/DWARFLinker/Parallel/DWARFLinkerUnit.h
@@ -17,6 +17,8 @@
 #include "llvm/DWARFLinker/StringPool.h"
 #include "llvm/DebugInfo/DWARF/DWARFUnit.h"
 #include "llvm/Support/LEB128.h"
+#include <memory>
+#include <mutex>
 
 namespace llvm {
 namespace dwarf_linker {
@@ -213,11 +215,18 @@ class DwarfUnit : public OutputSections {
   /// Output unit DIE.
   DIE *OutUnitDIE = nullptr;
 
-  /// Cache for file names for this unit.
+  /// Cache for file names for this unit. Entries are heap-allocated so the
+  /// StringRefs handed out by getDirAndFilenameFromLineTable keep pointing at
+  /// valid storage when a later insertion rehashes the map.
   using FileNamesCache =
-      DenseMap<uint64_t, std::pair<std::string, std::string>>;
+      DenseMap<uint64_t, std::unique_ptr<std::pair<std::string, std::string>>>;
   FileNamesCache FileNames;
 
+  /// Guards FileNames. During the parallel type-name assignment phase a unit's
+  /// cache is filled both by its own worker and, through cross-unit type-name
+  /// references, by other units' workers, so access must be serialized.
+  std::mutex FileNamesMutex;
+
   /// Maps a string into the index inside .debug_str_offsets section.
   IndexedValuesMap<const StringEntry *> DebugStringIndexMap;
 };


        


More information about the llvm-commits mailing list