diff --git a/llvm/lib/DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp b/llvm/lib/DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp --- a/llvm/lib/DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp @@ -38,18 +38,28 @@ DWARFAbbreviationDeclaration::extract(DataExtractor Data, uint64_t *OffsetPtr) { clear(); const uint64_t Offset = *OffsetPtr; - Code = Data.getULEB128(OffsetPtr); + Error Err = Error::success(); + Code = Data.getULEB128(OffsetPtr, &Err); + if (Err) + return Err; + if (Code == 0) return ExtractState::Complete; CodeByteSize = *OffsetPtr - Offset; - Tag = static_cast(Data.getULEB128(OffsetPtr)); + Tag = static_cast(Data.getULEB128(OffsetPtr, &Err)); + if (Err) + return Err; + if (Tag == DW_TAG_null) { clear(); return make_error( "abbreviation declaration requires a non-null tag"); } - uint8_t ChildrenByte = Data.getU8(OffsetPtr); + uint8_t ChildrenByte = Data.getU8(OffsetPtr, &Err); + if (Err) + return Err; + HasChildren = (ChildrenByte == DW_CHILDREN_yes); // Assign a value to our optional FixedAttributeSize member variable. If // this member variable still has a value after the while loop below, then @@ -58,8 +68,13 @@ // Read all of the abbreviation attributes and forms. while (Data.isValidOffset(*OffsetPtr)) { - auto A = static_cast(Data.getULEB128(OffsetPtr)); - auto F = static_cast
(Data.getULEB128(OffsetPtr)); + auto A = static_cast(Data.getULEB128(OffsetPtr, &Err)); + if (Err) + return Err; + + auto F = static_cast(Data.getULEB128(OffsetPtr, &Err)); + if (Err) + return Err; // We successfully reached the end of this abbreviation declaration // since both attribute and form are zero. There may be more abbreviation diff --git a/llvm/unittests/DebugInfo/DWARF/DWARFDebugAbbrevTest.cpp b/llvm/unittests/DebugInfo/DWARF/DWARFDebugAbbrevTest.cpp --- a/llvm/unittests/DebugInfo/DWARF/DWARFDebugAbbrevTest.cpp +++ b/llvm/unittests/DebugInfo/DWARF/DWARFDebugAbbrevTest.cpp @@ -42,6 +42,16 @@ encodeULEB128(0, OS); } +void writeMalformedULEB128Value(raw_ostream &OS) { + OS << static_cast(0x80); +} + +void writeULEB128LargerThan64Bits(raw_ostream &OS) { + static constexpr llvm::StringRef LargeULEB128 = + "\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x01"; + OS << LargeULEB128; +} + TEST(DWARFDebugAbbrevTest, DWARFAbbrevDeclSetExtractSuccess) { SmallString<64> RawData; raw_svector_ostream OS(RawData); @@ -104,3 +114,168 @@ EXPECT_FALSE(Abbrev1->hasChildren()); EXPECT_EQ(Abbrev1->getNumAttributes(), 1u); } + +TEST(DWARFDebugAbbrevTest, DWARFAbbreviationDeclSetCodeExtractionError) { + SmallString<64> RawData; + + // Check for malformed ULEB128. + { + raw_svector_ostream OS(RawData); + writeMalformedULEB128Value(OS); + + uint64_t Offset = 0; + DataExtractor Data(RawData, sys::IsLittleEndianHost, sizeof(uint64_t)); + DWARFAbbreviationDeclarationSet AbbrevSet; + EXPECT_FALSE(AbbrevSet.extract(Data, &Offset)); + EXPECT_EQ(Offset, 0u); + } + + RawData.clear(); + // Check for ULEB128 too large to fit into a uin64_t. + { + raw_svector_ostream OS(RawData); + writeULEB128LargerThan64Bits(OS); + + uint64_t Offset = 0; + DataExtractor Data(RawData, sys::IsLittleEndianHost, sizeof(uint64_t)); + DWARFAbbreviationDeclarationSet AbbrevSet; + EXPECT_FALSE(AbbrevSet.extract(Data, &Offset)); + EXPECT_EQ(Offset, 0u); + } +} + +TEST(DWARFDebugAbbrevTest, DWARFAbbreviationDeclSetTagExtractionError) { + SmallString<64> RawData; + const uint32_t Code = 1; + + // Check for malformed ULEB128. + { + raw_svector_ostream OS(RawData); + encodeULEB128(Code, OS); + writeMalformedULEB128Value(OS); + + uint64_t Offset = 0; + DataExtractor Data(RawData, sys::IsLittleEndianHost, sizeof(uint64_t)); + DWARFAbbreviationDeclarationSet AbbrevSet; + EXPECT_TRUE(AbbrevSet.extract(Data, &Offset)); + // Only the code was extracted correctly. + EXPECT_EQ(Offset, 1u); + } + + RawData.clear(); + // Check for ULEB128 too large to fit into a uint64_t. + { + raw_svector_ostream OS(RawData); + encodeULEB128(Code, OS); + writeULEB128LargerThan64Bits(OS); + + uint64_t Offset = 0; + DataExtractor Data(RawData, sys::IsLittleEndianHost, sizeof(uint64_t)); + DWARFAbbreviationDeclarationSet AbbrevSet; + EXPECT_TRUE(AbbrevSet.extract(Data, &Offset)); + // Only the code was extracted correctly. + EXPECT_EQ(Offset, 1u); + } +} + +TEST(DWARFDebugAbbrevTest, DWARFAbbreviatioDeclSetChildExtractionError) { + SmallString<64> RawData; + const uint32_t Code = 1; + const dwarf::Tag Tag = DW_TAG_compile_unit; + + // We want to make sure that we fail if we reach the end of the stream before + // reading the 'children' byte. + raw_svector_ostream OS(RawData); + encodeULEB128(Code, OS); + encodeULEB128(Tag, OS); + + uint64_t Offset = 0; + DataExtractor Data(RawData, sys::IsLittleEndianHost, sizeof(uint64_t)); + DWARFAbbreviationDeclarationSet AbbrevSet; + EXPECT_TRUE(AbbrevSet.extract(Data, &Offset)); + // The code and the tag were extracted correctly. + EXPECT_EQ(Offset, 2u); +} + +TEST(DWARFDebugAbbrevTest, DWARFAbbreviationDeclSetAttributeExtractionError) { + SmallString<64> RawData; + const uint32_t Code = 1; + const dwarf::Tag Tag = DW_TAG_compile_unit; + const uint8_t Children = DW_CHILDREN_yes; + + // Check for malformed ULEB128. + { + raw_svector_ostream OS(RawData); + encodeULEB128(Code, OS); + encodeULEB128(Tag, OS); + OS << Children; + writeMalformedULEB128Value(OS); + + uint64_t Offset = 0; + DataExtractor Data(RawData, sys::IsLittleEndianHost, sizeof(uint64_t)); + DWARFAbbreviationDeclarationSet AbbrevSet; + EXPECT_TRUE(AbbrevSet.extract(Data, &Offset)); + // The code, tag, and child byte were extracted correctly. + EXPECT_EQ(Offset, 3u); + } + + RawData.clear(); + // Check for ULEB128 too large to fit into a uint64_t. + { + raw_svector_ostream OS(RawData); + encodeULEB128(Code, OS); + encodeULEB128(Tag, OS); + OS << Children; + writeULEB128LargerThan64Bits(OS); + + uint64_t Offset = 0; + DataExtractor Data(RawData, sys::IsLittleEndianHost, sizeof(uint64_t)); + DWARFAbbreviationDeclarationSet AbbrevSet; + EXPECT_TRUE(AbbrevSet.extract(Data, &Offset)); + // The code, tag, and child byte were extracted correctly. + EXPECT_EQ(Offset, 3u); + } +} + +TEST(DWARFDebugAbbrevTest, DWARFAbbreviationDeclSetFormExtractionError) { + SmallString<64> RawData; + const uint32_t Code = 1; + const dwarf::Tag Tag = DW_TAG_compile_unit; + const uint8_t Children = DW_CHILDREN_yes; + const dwarf::Attribute Attr = DW_AT_name; + + // Check for malformed ULEB128. + { + raw_svector_ostream OS(RawData); + encodeULEB128(Code, OS); + encodeULEB128(Tag, OS); + OS << Children; + encodeULEB128(Attr, OS); + writeMalformedULEB128Value(OS); + + uint64_t Offset = 0; + DataExtractor Data(RawData, sys::IsLittleEndianHost, sizeof(uint64_t)); + DWARFAbbreviationDeclarationSet AbbrevSet; + EXPECT_TRUE(AbbrevSet.extract(Data, &Offset)); + // The code, tag, child byte, and first attribute were extracted correctly. + EXPECT_EQ(Offset, 4u); + } + + RawData.clear(); + // Check for ULEB128 too large to fit into a uint64_t. + { + raw_svector_ostream OS(RawData); + encodeULEB128(Code, OS); + encodeULEB128(Tag, OS); + OS << Children; + encodeULEB128(Attr, OS); + writeULEB128LargerThan64Bits(OS); + + uint64_t Offset = 0; + DataExtractor Data(RawData, sys::IsLittleEndianHost, sizeof(uint64_t)); + DWARFAbbreviationDeclarationSet AbbrevSet; + EXPECT_TRUE(AbbrevSet.extract(Data, &Offset)); + // The code, tag, child byte, and first attribute were extracted correctly. + EXPECT_EQ(Offset, 4u); + } +}