[llvm] 211ee04 - [llvm-debuginfo-analyzer] Fix a couple of unhandled DWARF situations leading to a crash (#137221)

via llvm-commits llvm-commits at lists.llvm.org
Tue May 20 21:29:45 PDT 2025


Author: Javier Lopez-Gomez
Date: 2025-05-21T05:29:41+01:00
New Revision: 211ee04a616b0071adefe57015daf5702b0a09b4

URL: https://github.com/llvm/llvm-project/commit/211ee04a616b0071adefe57015daf5702b0a09b4
DIFF: https://github.com/llvm/llvm-project/commit/211ee04a616b0071adefe57015daf5702b0a09b4.diff

LOG: [llvm-debuginfo-analyzer] Fix a couple of unhandled DWARF situations leading to a crash (#137221)

This pull request fixes a couple of unhandled situations in DWARF input
leading to a crash. Specifically,

- If the DWARF input contains a declaration of a C variadic function
(where `...` translates to `DW_TAG_unspecified_parameters`), which is
then followed by a definition, `llvm_unreachable()` is hit in
`LVScope::addMissingElements()`. This is only visible in Debug builds.

- Parsing of instructions in `LVBinaryReader::createInstructions()` does
not check whether `Offset` lies within the `Bytes` ArrayRef. A specially
crafted DWARF input can lead to this condition.

Added: 
    llvm/unittests/DebugInfo/LogicalView/Inputs/test-dwarf-clang-unspec-params.elf

Modified: 
    llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp
    llvm/lib/DebugInfo/LogicalView/Readers/LVBinaryReader.cpp
    llvm/unittests/DebugInfo/LogicalView/DWARFReaderTest.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp
index e1ea5da4dc51a..594b6816f14c5 100644
--- a/llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp
@@ -330,13 +330,16 @@ void LVScope::addMissingElements(LVScope *Reference) {
       Symbol->setIsOptimized();
       Symbol->setReference(Reference);
 
-      // The symbol can be a constant, parameter or variable.
+      // The symbol can be a constant, parameter, variable or unspecified
+      // parameters (i.e. `...`).
       if (Reference->getIsConstant())
         Symbol->setIsConstant();
       else if (Reference->getIsParameter())
         Symbol->setIsParameter();
       else if (Reference->getIsVariable())
         Symbol->setIsVariable();
+      else if (Reference->getIsUnspecified())
+        Symbol->setIsUnspecified();
       else
         llvm_unreachable("Invalid symbol kind.");
     }

diff  --git a/llvm/lib/DebugInfo/LogicalView/Readers/LVBinaryReader.cpp b/llvm/lib/DebugInfo/LogicalView/Readers/LVBinaryReader.cpp
index cad53b8079e70..434709f076dc5 100644
--- a/llvm/lib/DebugInfo/LogicalView/Readers/LVBinaryReader.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/Readers/LVBinaryReader.cpp
@@ -433,6 +433,15 @@ Error LVBinaryReader::createInstructions(LVScope *Scope,
 
   ArrayRef<uint8_t> Bytes = arrayRefFromStringRef(*SectionContentsOrErr);
   uint64_t Offset = Address - SectionAddress;
+  if (Offset > Bytes.size()) {
+    LLVM_DEBUG({
+      dbgs() << "offset (" << hexValue(Offset) << ") is beyond section size ("
+             << hexValue(Bytes.size()) << "); malformed input?\n";
+    });
+    return createStringError(
+        errc::bad_address,
+        "Failed to parse instructions; offset beyond section size");
+  }
   uint8_t const *Begin = Bytes.data() + Offset;
   uint8_t const *End = Bytes.data() + Offset + Size;
 

diff  --git a/llvm/unittests/DebugInfo/LogicalView/DWARFReaderTest.cpp b/llvm/unittests/DebugInfo/LogicalView/DWARFReaderTest.cpp
index c062c15481da9..03bf394631c99 100644
--- a/llvm/unittests/DebugInfo/LogicalView/DWARFReaderTest.cpp
+++ b/llvm/unittests/DebugInfo/LogicalView/DWARFReaderTest.cpp
@@ -30,6 +30,9 @@ extern const char *TestMainArgv0;
 namespace {
 
 const char *DwarfClang = "test-dwarf-clang.o";
+// Two compile units: one declares `extern int foo_printf(const char *, ...);`
+// and another one that defines the function.
+const char *DwarfClangUnspecParams = "test-dwarf-clang-unspec-params.elf";
 const char *DwarfGcc = "test-dwarf-gcc.o";
 
 // Helper function to get the first compile unit.
@@ -37,7 +40,7 @@ LVScopeCompileUnit *getFirstCompileUnit(LVScopeRoot *Root) {
   EXPECT_NE(Root, nullptr);
   const LVScopes *CompileUnits = Root->getScopes();
   EXPECT_NE(CompileUnits, nullptr);
-  EXPECT_EQ(CompileUnits->size(), 1u);
+  EXPECT_GT(CompileUnits->size(), 0u);
 
   LVScopes::const_iterator Iter = CompileUnits->begin();
   EXPECT_NE(Iter, nullptr);
@@ -124,6 +127,36 @@ void checkElementProperties(LVReader *Reader) {
   ASSERT_EQ(Lines->size(), 0x12u);
 }
 
+// Check proper handling of DW_AT_unspecified_parameters in
+// LVScope::addMissingElements().
+void checkUnspecifiedParameters(LVReader *Reader) {
+  LVScopeRoot *Root = Reader->getScopesRoot();
+  LVScopeCompileUnit *CompileUnit = getFirstCompileUnit(Root);
+
+  EXPECT_EQ(Root->getFileFormatName(), "elf64-x86-64");
+  EXPECT_EQ(Root->getName(), DwarfClangUnspecParams);
+
+  const LVPublicNames &PublicNames = CompileUnit->getPublicNames();
+  ASSERT_EQ(PublicNames.size(), 1u);
+
+  LVPublicNames::const_iterator IterNames = PublicNames.cbegin();
+  LVScope *Function = (*IterNames).first;
+  EXPECT_EQ(Function->getName(), "foo_printf");
+  const LVElements *Elements = Function->getChildren();
+  ASSERT_NE(Elements, nullptr);
+  // foo_printf is a variadic function whose prototype is
+  // `int foo_printf(const char *, ...)`, where the '...' is represented by a
+  // DW_TAG_unspecified_parameters, i.e. we expect to find at least one child
+  // for which getIsUnspecified() returns true.
+  EXPECT_EQ(std::any_of(
+                Elements->begin(), Elements->end(),
+                [](const LVElement *elt) {
+                  return elt->getIsSymbol() &&
+                         static_cast<const LVSymbol *>(elt)->getIsUnspecified();
+                }),
+            true);
+}
+
 // Check the logical elements selection.
 void checkElementSelection(LVReader *Reader) {
   LVScopeRoot *Root = Reader->getScopesRoot();
@@ -253,6 +286,7 @@ void elementProperties(SmallString<128> &InputsDir) {
   ReaderOptions.setAttributePublics();
   ReaderOptions.setAttributeRange();
   ReaderOptions.setAttributeLocation();
+  ReaderOptions.setAttributeInserted();
   ReaderOptions.setPrintAll();
   ReaderOptions.resolveDependencies();
 
@@ -264,6 +298,9 @@ void elementProperties(SmallString<128> &InputsDir) {
   std::unique_ptr<LVReader> Reader =
       createReader(ReaderHandler, InputsDir, DwarfClang);
   checkElementProperties(Reader.get());
+
+  Reader = createReader(ReaderHandler, InputsDir, DwarfClangUnspecParams);
+  checkUnspecifiedParameters(Reader.get());
 }
 
 // Logical elements selection.

diff  --git a/llvm/unittests/DebugInfo/LogicalView/Inputs/test-dwarf-clang-unspec-params.elf b/llvm/unittests/DebugInfo/LogicalView/Inputs/test-dwarf-clang-unspec-params.elf
new file mode 100755
index 0000000000000..67c6e71fbf7b9
Binary files /dev/null and b/llvm/unittests/DebugInfo/LogicalView/Inputs/test-dwarf-clang-unspec-params.elf 
diff er


        


More information about the llvm-commits mailing list