Skip to content

Commit 211ee04

Browse files
authored
[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.
1 parent 9a553d3 commit 211ee04

File tree

4 files changed

+51
-2
lines changed

4 files changed

+51
-2
lines changed

llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -330,13 +330,16 @@ void LVScope::addMissingElements(LVScope *Reference) {
330330
Symbol->setIsOptimized();
331331
Symbol->setReference(Reference);
332332

333-
// The symbol can be a constant, parameter or variable.
333+
// The symbol can be a constant, parameter, variable or unspecified
334+
// parameters (i.e. `...`).
334335
if (Reference->getIsConstant())
335336
Symbol->setIsConstant();
336337
else if (Reference->getIsParameter())
337338
Symbol->setIsParameter();
338339
else if (Reference->getIsVariable())
339340
Symbol->setIsVariable();
341+
else if (Reference->getIsUnspecified())
342+
Symbol->setIsUnspecified();
340343
else
341344
llvm_unreachable("Invalid symbol kind.");
342345
}

llvm/lib/DebugInfo/LogicalView/Readers/LVBinaryReader.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,15 @@ Error LVBinaryReader::createInstructions(LVScope *Scope,
433433

434434
ArrayRef<uint8_t> Bytes = arrayRefFromStringRef(*SectionContentsOrErr);
435435
uint64_t Offset = Address - SectionAddress;
436+
if (Offset > Bytes.size()) {
437+
LLVM_DEBUG({
438+
dbgs() << "offset (" << hexValue(Offset) << ") is beyond section size ("
439+
<< hexValue(Bytes.size()) << "); malformed input?\n";
440+
});
441+
return createStringError(
442+
errc::bad_address,
443+
"Failed to parse instructions; offset beyond section size");
444+
}
436445
uint8_t const *Begin = Bytes.data() + Offset;
437446
uint8_t const *End = Bytes.data() + Offset + Size;
438447

llvm/unittests/DebugInfo/LogicalView/DWARFReaderTest.cpp

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,17 @@ extern const char *TestMainArgv0;
3030
namespace {
3131

3232
const char *DwarfClang = "test-dwarf-clang.o";
33+
// Two compile units: one declares `extern int foo_printf(const char *, ...);`
34+
// and another one that defines the function.
35+
const char *DwarfClangUnspecParams = "test-dwarf-clang-unspec-params.elf";
3336
const char *DwarfGcc = "test-dwarf-gcc.o";
3437

3538
// Helper function to get the first compile unit.
3639
LVScopeCompileUnit *getFirstCompileUnit(LVScopeRoot *Root) {
3740
EXPECT_NE(Root, nullptr);
3841
const LVScopes *CompileUnits = Root->getScopes();
3942
EXPECT_NE(CompileUnits, nullptr);
40-
EXPECT_EQ(CompileUnits->size(), 1u);
43+
EXPECT_GT(CompileUnits->size(), 0u);
4144

4245
LVScopes::const_iterator Iter = CompileUnits->begin();
4346
EXPECT_NE(Iter, nullptr);
@@ -124,6 +127,36 @@ void checkElementProperties(LVReader *Reader) {
124127
ASSERT_EQ(Lines->size(), 0x12u);
125128
}
126129

130+
// Check proper handling of DW_AT_unspecified_parameters in
131+
// LVScope::addMissingElements().
132+
void checkUnspecifiedParameters(LVReader *Reader) {
133+
LVScopeRoot *Root = Reader->getScopesRoot();
134+
LVScopeCompileUnit *CompileUnit = getFirstCompileUnit(Root);
135+
136+
EXPECT_EQ(Root->getFileFormatName(), "elf64-x86-64");
137+
EXPECT_EQ(Root->getName(), DwarfClangUnspecParams);
138+
139+
const LVPublicNames &PublicNames = CompileUnit->getPublicNames();
140+
ASSERT_EQ(PublicNames.size(), 1u);
141+
142+
LVPublicNames::const_iterator IterNames = PublicNames.cbegin();
143+
LVScope *Function = (*IterNames).first;
144+
EXPECT_EQ(Function->getName(), "foo_printf");
145+
const LVElements *Elements = Function->getChildren();
146+
ASSERT_NE(Elements, nullptr);
147+
// foo_printf is a variadic function whose prototype is
148+
// `int foo_printf(const char *, ...)`, where the '...' is represented by a
149+
// DW_TAG_unspecified_parameters, i.e. we expect to find at least one child
150+
// for which getIsUnspecified() returns true.
151+
EXPECT_EQ(std::any_of(
152+
Elements->begin(), Elements->end(),
153+
[](const LVElement *elt) {
154+
return elt->getIsSymbol() &&
155+
static_cast<const LVSymbol *>(elt)->getIsUnspecified();
156+
}),
157+
true);
158+
}
159+
127160
// Check the logical elements selection.
128161
void checkElementSelection(LVReader *Reader) {
129162
LVScopeRoot *Root = Reader->getScopesRoot();
@@ -253,6 +286,7 @@ void elementProperties(SmallString<128> &InputsDir) {
253286
ReaderOptions.setAttributePublics();
254287
ReaderOptions.setAttributeRange();
255288
ReaderOptions.setAttributeLocation();
289+
ReaderOptions.setAttributeInserted();
256290
ReaderOptions.setPrintAll();
257291
ReaderOptions.resolveDependencies();
258292

@@ -264,6 +298,9 @@ void elementProperties(SmallString<128> &InputsDir) {
264298
std::unique_ptr<LVReader> Reader =
265299
createReader(ReaderHandler, InputsDir, DwarfClang);
266300
checkElementProperties(Reader.get());
301+
302+
Reader = createReader(ReaderHandler, InputsDir, DwarfClangUnspecParams);
303+
checkUnspecifiedParameters(Reader.get());
267304
}
268305

269306
// Logical elements selection.
Binary file not shown.

0 commit comments

Comments
 (0)