diff --git a/llvm/include/llvm/Support/DataExtractor.h b/llvm/include/llvm/Support/DataExtractor.h --- a/llvm/include/llvm/Support/DataExtractor.h +++ b/llvm/include/llvm/Support/DataExtractor.h @@ -689,6 +689,16 @@ // public. static uint64_t &getOffset(Cursor &C) { return C.Offset; } static Error &getError(Cursor &C) { return C.Err; } + + /// If it is possible to read \a Size bytes at offset \a Offset, returns \b + /// true. Otherwise, returns \b false. If \a E is not nullptr, also sets the + /// error object to indicate an error. + bool prepareRead(uint64_t Offset, uint64_t Size, Error *E) const; + +private: + template T getU(uint64_t *OffsetPtr, Error *Err) const; + template + T *getUs(uint64_t *OffsetPtr, T *Dst, uint32_t Count, Error *Err) const; }; } // namespace llvm diff --git a/llvm/lib/Support/DataExtractor.cpp b/llvm/lib/Support/DataExtractor.cpp --- a/llvm/lib/Support/DataExtractor.cpp +++ b/llvm/lib/Support/DataExtractor.cpp @@ -15,30 +15,33 @@ using namespace llvm; -static void unexpectedEndReached(Error *E, uint64_t Offset) { +bool DataExtractor::prepareRead(uint64_t Offset, uint64_t Size, + Error *E) const { + if (isValidOffsetForDataOfSize(Offset, Size)) + return true; if (E) - *E = createStringError(errc::illegal_byte_sequence, - "unexpected end of data at offset 0x%" PRIx64, - Offset); + *E = createStringError( + errc::illegal_byte_sequence, + "unexpected end of data at offset 0x%zx while reading [0x%" PRIx64 + ", 0x%" PRIx64 ")", + Data.size(), Offset, Offset + Size); + return false; } static bool isError(Error *E) { return E && *E; } template -static T getU(uint64_t *offset_ptr, const DataExtractor *de, - bool isLittleEndian, const char *Data, llvm::Error *Err) { +T DataExtractor::getU(uint64_t *offset_ptr, Error *Err) const { ErrorAsOutParameter ErrAsOut(Err); T val = 0; if (isError(Err)) return val; uint64_t offset = *offset_ptr; - if (!de->isValidOffsetForDataOfSize(offset, sizeof(T))) { - unexpectedEndReached(Err, offset); + if (!prepareRead(offset, sizeof(T), Err)) return val; - } - std::memcpy(&val, &Data[offset], sizeof(val)); - if (sys::IsLittleEndianHost != isLittleEndian) + std::memcpy(&val, &Data.data()[offset], sizeof(val)); + if (sys::IsLittleEndianHost != IsLittleEndian) sys::swapByteOrder(val); // Advance the offset @@ -47,22 +50,19 @@ } template -static T *getUs(uint64_t *offset_ptr, T *dst, uint32_t count, - const DataExtractor *de, bool isLittleEndian, const char *Data, - llvm::Error *Err) { +T *DataExtractor::getUs(uint64_t *offset_ptr, T *dst, uint32_t count, + Error *Err) const { ErrorAsOutParameter ErrAsOut(Err); if (isError(Err)) return nullptr; uint64_t offset = *offset_ptr; - if (!de->isValidOffsetForDataOfSize(offset, sizeof(*dst) * count)) { - unexpectedEndReached(Err, offset); + if (!prepareRead(offset, sizeof(*dst) * count, Err)) return nullptr; - } for (T *value_ptr = dst, *end = dst + count; value_ptr != end; ++value_ptr, offset += sizeof(*dst)) - *value_ptr = getU(offset_ptr, de, isLittleEndian, Data, Err); + *value_ptr = getU(offset_ptr, Err); // Advance the offset *offset_ptr = offset; // Return a non-NULL pointer to the converted data as an indicator of @@ -71,55 +71,49 @@ } uint8_t DataExtractor::getU8(uint64_t *offset_ptr, llvm::Error *Err) const { - return getU(offset_ptr, this, IsLittleEndian, Data.data(), Err); + return getU(offset_ptr, Err); } -uint8_t * -DataExtractor::getU8(uint64_t *offset_ptr, uint8_t *dst, uint32_t count) const { - return getUs(offset_ptr, dst, count, this, IsLittleEndian, - Data.data(), nullptr); +uint8_t *DataExtractor::getU8(uint64_t *offset_ptr, uint8_t *dst, + uint32_t count) const { + return getUs(offset_ptr, dst, count, nullptr); } uint8_t *DataExtractor::getU8(Cursor &C, uint8_t *Dst, uint32_t Count) const { - return getUs(&C.Offset, Dst, Count, this, IsLittleEndian, - Data.data(), &C.Err); + return getUs(&C.Offset, Dst, Count, &C.Err); } uint16_t DataExtractor::getU16(uint64_t *offset_ptr, llvm::Error *Err) const { - return getU(offset_ptr, this, IsLittleEndian, Data.data(), Err); + return getU(offset_ptr, Err); } uint16_t *DataExtractor::getU16(uint64_t *offset_ptr, uint16_t *dst, uint32_t count) const { - return getUs(offset_ptr, dst, count, this, IsLittleEndian, - Data.data(), nullptr); + return getUs(offset_ptr, dst, count, nullptr); } uint32_t DataExtractor::getU24(uint64_t *OffsetPtr, Error *Err) const { - uint24_t ExtractedVal = - getU(OffsetPtr, this, IsLittleEndian, Data.data(), Err); + uint24_t ExtractedVal = getU(OffsetPtr, Err); // The 3 bytes are in the correct byte order for the host. return ExtractedVal.getAsUint32(sys::IsLittleEndianHost); } uint32_t DataExtractor::getU32(uint64_t *offset_ptr, llvm::Error *Err) const { - return getU(offset_ptr, this, IsLittleEndian, Data.data(), Err); + return getU(offset_ptr, Err); } uint32_t *DataExtractor::getU32(uint64_t *offset_ptr, uint32_t *dst, uint32_t count) const { - return getUs(offset_ptr, dst, count, this, IsLittleEndian, - Data.data(), nullptr); + return getUs(offset_ptr, dst, count, nullptr); } uint64_t DataExtractor::getU64(uint64_t *offset_ptr, llvm::Error *Err) const { - return getU(offset_ptr, this, IsLittleEndian, Data.data(), Err); + return getU(offset_ptr, Err); } uint64_t *DataExtractor::getU64(uint64_t *offset_ptr, uint64_t *dst, uint32_t count) const { - return getUs(offset_ptr, dst, count, this, IsLittleEndian, - Data.data(), nullptr); + return getUs(offset_ptr, dst, count, nullptr); } uint64_t DataExtractor::getUnsigned(uint64_t *offset_ptr, uint32_t byte_size, @@ -163,7 +157,10 @@ *OffsetPtr = Pos + 1; return StringRef(Data.data() + Start, Pos - Start); } - unexpectedEndReached(Err, Start); + if (Err) + *Err = createStringError(errc::illegal_byte_sequence, + "no null terminated string at offset 0x%" PRIx64, + Start); return StringRef(); } @@ -180,10 +177,8 @@ if (isError(Err)) return StringRef(); - if (!isValidOffsetForDataOfSize(*OffsetPtr, Length)) { - unexpectedEndReached(Err, *OffsetPtr); + if (!prepareRead(*OffsetPtr, Length, Err)) return StringRef(); - } StringRef Result = Data.substr(*OffsetPtr, Length); *OffsetPtr += Length; @@ -226,8 +221,6 @@ if (isError(&C.Err)) return; - if (isValidOffsetForDataOfSize(C.Offset, Length)) + if (prepareRead(C.Offset, Length, &C.Err)) C.Offset += Length; - else - unexpectedEndReached(&C.Err, C.Offset); } diff --git a/llvm/test/DebugInfo/X86/dwarfdump-debug-loc-error-cases2.s b/llvm/test/DebugInfo/X86/dwarfdump-debug-loc-error-cases2.s --- a/llvm/test/DebugInfo/X86/dwarfdump-debug-loc-error-cases2.s +++ b/llvm/test/DebugInfo/X86/dwarfdump-debug-loc-error-cases2.s @@ -9,7 +9,7 @@ # CHECK: DW_AT_name ("x1") # CHECK-NEXT: DW_AT_location (0xdeadbeef: ) -# ERR: error: unexpected end of data at offset 0xdeadbeef +# ERR: error: unexpected end of data at offset 0x48 while reading [0xdeadbeef, 0xdeadbef7) # CHECK: DW_AT_name ("x2") # CHECK-NEXT: DW_AT_location (0x00000036: ) diff --git a/llvm/test/DebugInfo/X86/dwarfdump-debug-loclists-error-cases2.s b/llvm/test/DebugInfo/X86/dwarfdump-debug-loclists-error-cases2.s --- a/llvm/test/DebugInfo/X86/dwarfdump-debug-loclists-error-cases2.s +++ b/llvm/test/DebugInfo/X86/dwarfdump-debug-loclists-error-cases2.s @@ -9,7 +9,7 @@ # CHECK: DW_AT_name ("x1") # CHECK-NEXT: DW_AT_location (0xdeadbeef: ) -# ERR: error: unexpected end of data at offset 0xdeadbeef +# ERR: error: unexpected end of data at offset 0x34 while reading [0xdeadbeef, 0xdeadbef0) # CHECK: DW_AT_name ("x2") # CHECK-NEXT: DW_AT_location (0x00000025 diff --git a/llvm/test/tools/llvm-dwarfdump/X86/debug_addr_too_small_for_extended_length_field.s b/llvm/test/tools/llvm-dwarfdump/X86/debug_addr_too_small_for_extended_length_field.s --- a/llvm/test/tools/llvm-dwarfdump/X86/debug_addr_too_small_for_extended_length_field.s +++ b/llvm/test/tools/llvm-dwarfdump/X86/debug_addr_too_small_for_extended_length_field.s @@ -4,7 +4,7 @@ # CHECK: .debug_addr contents: # CHECK-NOT: {{.}} -# ERR: parsing address table at offset 0x0: unexpected end of data at offset 0x4 +# ERR: parsing address table at offset 0x0: unexpected end of data at offset 0xb while reading [0x4, 0xc) # ERR-NOT: {{.}} # too small section to contain an extended length field of a DWARF64 address table. diff --git a/llvm/test/tools/llvm-dwarfdump/X86/debug_addr_too_small_for_length_field.s b/llvm/test/tools/llvm-dwarfdump/X86/debug_addr_too_small_for_length_field.s --- a/llvm/test/tools/llvm-dwarfdump/X86/debug_addr_too_small_for_length_field.s +++ b/llvm/test/tools/llvm-dwarfdump/X86/debug_addr_too_small_for_length_field.s @@ -4,7 +4,7 @@ # CHECK: .debug_addr contents: # CHECK-NOT: {{.}} -# ERR: parsing address table at offset 0x0: unexpected end of data at offset 0x0 +# ERR: parsing address table at offset 0x0: unexpected end of data at offset 0x2 while reading [0x0, 0x4) # ERR-NOT: {{.}} # too small section to contain length field diff --git a/llvm/test/tools/llvm-dwarfdump/X86/debug_rnglists_invalid.s b/llvm/test/tools/llvm-dwarfdump/X86/debug_rnglists_invalid.s --- a/llvm/test/tools/llvm-dwarfdump/X86/debug_rnglists_invalid.s +++ b/llvm/test/tools/llvm-dwarfdump/X86/debug_rnglists_invalid.s @@ -2,7 +2,7 @@ # RUN: not llvm-dwarfdump --debug-rnglists - 2>&1 | FileCheck %s --check-prefix=SHORT # SHORT-NOT: error: # SHORT-NOT: range list header -# SHORT: error: parsing .debug_rnglists table at offset 0x0: unexpected end of data at offset 0x0 +# SHORT: error: parsing .debug_rnglists table at offset 0x0: unexpected end of data at offset 0x3 # SHORT-NOT: range list header # SHORT-NOT: error: diff --git a/llvm/unittests/DebugInfo/DWARF/DWARFAcceleratorTableTest.cpp b/llvm/unittests/DebugInfo/DWARF/DWARFAcceleratorTableTest.cpp --- a/llvm/unittests/DebugInfo/DWARF/DWARFAcceleratorTableTest.cpp +++ b/llvm/unittests/DebugInfo/DWARF/DWARFAcceleratorTableTest.cpp @@ -43,7 +43,7 @@ ExtractDebugNames(StringRef(NamesSecData, sizeof(NamesSecData)), StringRef()), FailedWithMessage("parsing .debug_names header at 0x0: unexpected end of " - "data at offset 0x28")); + "data at offset 0x2b while reading [0x28, 0x2c)")); } } // end anonymous namespace diff --git a/llvm/unittests/DebugInfo/DWARF/DWARFDataExtractorTest.cpp b/llvm/unittests/DebugInfo/DWARF/DWARFDataExtractorTest.cpp --- a/llvm/unittests/DebugInfo/DWARF/DWARFDataExtractorTest.cpp +++ b/llvm/unittests/DebugInfo/DWARF/DWARFDataExtractorTest.cpp @@ -61,8 +61,10 @@ DataExtractor::Cursor C(0); EXPECT_EQ(0x42u, Data.getRelocatedAddress(C)); EXPECT_EQ(0u, Data.getRelocatedAddress(C)); - EXPECT_THAT_ERROR(C.takeError(), - FailedWithMessage("unexpected end of data at offset 0x4")); + EXPECT_THAT_ERROR( + C.takeError(), + FailedWithMessage( + "unexpected end of data at offset 0x6 while reading [0x4, 0x8)")); } TEST(DWARFDataExtractorTest, getInitialLength) { @@ -94,13 +96,15 @@ // Empty data. EXPECT_THAT_EXPECTED( GetWithError({}), - FailedWithMessage("unexpected end of data at offset 0x0")); + FailedWithMessage( + "unexpected end of data at offset 0x0 while reading [0x0, 0x4)")); EXPECT_EQ(GetWithoutError({}), ErrorResult); // Not long enough for the U32 field. EXPECT_THAT_EXPECTED( GetWithError({0x00, 0x01, 0x02}), - FailedWithMessage("unexpected end of data at offset 0x0")); + FailedWithMessage( + "unexpected end of data at offset 0x3 while reading [0x0, 0x4)")); EXPECT_EQ(GetWithoutError({0x00, 0x01, 0x02}), ErrorResult); EXPECT_THAT_EXPECTED( @@ -127,13 +131,15 @@ // DWARF64 marker without the subsequent length field. EXPECT_THAT_EXPECTED( GetWithError({0xff, 0xff, 0xff, 0xff}), - FailedWithMessage("unexpected end of data at offset 0x4")); + FailedWithMessage( + "unexpected end of data at offset 0x4 while reading [0x4, 0xc)")); EXPECT_EQ(GetWithoutError({0xff, 0xff, 0xff, 0xff}), ErrorResult); // Not enough data for the U64 length. EXPECT_THAT_EXPECTED( GetWithError({0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0x02, 0x03}), - FailedWithMessage("unexpected end of data at offset 0x4")); + FailedWithMessage( + "unexpected end of data at offset 0x8 while reading [0x4, 0xc)")); EXPECT_EQ(GetWithoutError({0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0x02, 0x03}), ErrorResult); diff --git a/llvm/unittests/DebugInfo/DWARF/DWARFDebugArangeSetTest.cpp b/llvm/unittests/DebugInfo/DWARF/DWARFDebugArangeSetTest.cpp --- a/llvm/unittests/DebugInfo/DWARF/DWARFDebugArangeSetTest.cpp +++ b/llvm/unittests/DebugInfo/DWARF/DWARFDebugArangeSetTest.cpp @@ -121,7 +121,7 @@ static const char DebugArangesSecRaw[11 + 1] = {0}; ExpectExtractError(DebugArangesSecRaw, "parsing address ranges table at offset 0x0: unexpected " - "end of data at offset 0xb"); + "end of data at offset 0xb while reading [0xb, 0xc)"); } TEST(DWARFDebugArangeSet, SectionTooShortDWARF64) { @@ -130,7 +130,7 @@ "\xff\xff\xff\xff"; // DWARF64 mark ExpectExtractError(DebugArangesSecRaw, "parsing address ranges table at offset 0x0: unexpected " - "end of data at offset 0x17"); + "end of data at offset 0x17 while reading [0x17, 0x18)"); } TEST(DWARFDebugArangeSet, NoSpaceForEntries) { diff --git a/llvm/unittests/DebugInfo/DWARF/DWARFDebugLineTest.cpp b/llvm/unittests/DebugInfo/DWARF/DWARFDebugLineTest.cpp --- a/llvm/unittests/DebugInfo/DWARF/DWARFDebugLineTest.cpp +++ b/llvm/unittests/DebugInfo/DWARF/DWARFDebugLineTest.cpp @@ -211,8 +211,9 @@ EXPECT_THAT_EXPECTED( getOrParseLineTableFatalErrors(0), - FailedWithMessage("parsing line table prologue at offset 0x00000000: " - "unexpected end of data at offset 0x0")); + FailedWithMessage( + "parsing line table prologue at offset 0x00000000: " + "unexpected end of data at offset 0x1 while reading [0x0, 0x4)")); EXPECT_THAT_EXPECTED( getOrParseLineTableFatalErrors(1), diff --git a/llvm/unittests/DebugInfo/DWARF/DWARFDieTest.cpp b/llvm/unittests/DebugInfo/DWARF/DWARFDieTest.cpp --- a/llvm/unittests/DebugInfo/DWARF/DWARFDieTest.cpp +++ b/llvm/unittests/DebugInfo/DWARF/DWARFDieTest.cpp @@ -107,7 +107,8 @@ EXPECT_THAT_EXPECTED( Die.getLocations(DW_AT_call_data_location), - FailedWithMessage("unexpected end of data at offset 0x20")); + FailedWithMessage( + "unexpected end of data at offset 0x20 while reading [0x20, 0x21)")); EXPECT_THAT_EXPECTED( Die.getLocations(DW_AT_call_data_value), diff --git a/llvm/unittests/Support/DataExtractorTest.cpp b/llvm/unittests/Support/DataExtractorTest.cpp --- a/llvm/unittests/Support/DataExtractorTest.cpp +++ b/llvm/unittests/Support/DataExtractorTest.cpp @@ -102,8 +102,9 @@ EXPECT_EQ(11U, C.tell()); EXPECT_EQ(nullptr, DE.getCStr(C)); EXPECT_EQ(11U, C.tell()); - EXPECT_THAT_ERROR(C.takeError(), - FailedWithMessage("unexpected end of data at offset 0xb")); + EXPECT_THAT_ERROR( + C.takeError(), + FailedWithMessage("no null terminated string at offset 0xb")); } TEST(DataExtractorTest, LEB128) {