diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDebugArangeSet.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugArangeSet.cpp --- a/llvm/lib/DebugInfo/DWARF/DWARFDebugArangeSet.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFDebugArangeSet.cpp @@ -59,9 +59,31 @@ // the segment selectors are omitted from all tuples, including // the terminating tuple. + constexpr unsigned CommonFieldsLength = 2 + // Version + 1 + // Address Size + 1; // Segment Selector Size + constexpr unsigned DWARF32HeaderLength = + dwarf::getUnitLengthFieldByteSize(dwarf::DWARF32) + CommonFieldsLength + + dwarf::getDwarfOffsetByteSize(dwarf::DWARF32); // Debug Info Offset + constexpr unsigned DWARF64HeaderLength = + dwarf::getUnitLengthFieldByteSize(dwarf::DWARF64) + CommonFieldsLength + + dwarf::getDwarfOffsetByteSize(dwarf::DWARF64); // Debug Info Offset + + if (!data.isValidOffsetForDataOfSize(Offset, DWARF32HeaderLength)) + return createStringError(errc::invalid_argument, + "section is not large enough to contain " + "an address range table at offset 0x%" PRIx64, + Offset); + dwarf::DwarfFormat format = dwarf::DWARF32; HeaderData.Length = data.getU32(offset_ptr); if (HeaderData.Length == dwarf::DW_LENGTH_DWARF64) { + if (!data.isValidOffsetForDataOfSize(Offset, DWARF64HeaderLength)) + return createStringError( + errc::invalid_argument, + "section is not large enough to contain a DWARF64 " + "address range table at offset 0x%" PRIx64, + Offset); HeaderData.Length = data.getU64(offset_ptr); format = dwarf::DWARF64; } else if (HeaderData.Length >= dwarf::DW_LENGTH_lo_reserved) { @@ -91,17 +113,38 @@ " has unsupported address size: %d " "(4 and 8 supported)", Offset, HeaderData.AddrSize); + if (HeaderData.SegSize != 0) + return createStringError(errc::not_supported, + "non-zero segment selector size in address range " + "table at offset 0x%" PRIx64 " is not supported", + Offset); - // The first tuple following the header in each set begins at an offset - // that is a multiple of the size of a single tuple (that is, twice the - // size of an address). The header is padded, if necessary, to the - // appropriate boundary. - const uint32_t header_size = *offset_ptr - Offset; + // The first tuple following the header in each set begins at an offset that + // is a multiple of the size of a single tuple (that is, twice the size of + // an address because we do not support non-zero segment selector sizes). + // Therefore, the full length should also be a multiple of the tuple size. const uint32_t tuple_size = HeaderData.AddrSize * 2; + if (full_length % tuple_size != 0) + return createStringError( + errc::invalid_argument, + "address range table at offset 0x%" PRIx64 + " has length that is not a multiple of the tuple size", + Offset); + + // The header is padded, if necessary, to the appropriate boundary. + const uint32_t header_size = *offset_ptr - Offset; uint32_t first_tuple_offset = 0; while (first_tuple_offset < header_size) first_tuple_offset += tuple_size; + // There should be space for at least one tuple. + if (full_length <= first_tuple_offset) + return createStringError( + errc::invalid_argument, + "address range table at offset 0x%" PRIx64 + " has an insufficient length to contain any entries", + Offset); + *offset_ptr = Offset + first_tuple_offset; Descriptor arangeDescriptor; @@ -111,14 +154,23 @@ "Different datatypes for addresses and sizes!"); assert(sizeof(arangeDescriptor.Address) >= HeaderData.AddrSize); - while (data.isValidOffset(*offset_ptr)) { + uint64_t end_offset = Offset + full_length; + while (*offset_ptr < end_offset) { arangeDescriptor.Address = data.getUnsigned(offset_ptr, HeaderData.AddrSize); arangeDescriptor.Length = data.getUnsigned(offset_ptr, HeaderData.AddrSize); - // Each set of tuples is terminated by a 0 for the address and 0 - // for the length. - if (arangeDescriptor.Address == 0 && arangeDescriptor.Length == 0) - return ErrorSuccess(); + if (arangeDescriptor.Length == 0) { + // Each set of tuples is terminated by a 0 for the address and 0 + // for the length. + if (arangeDescriptor.Address == 0 && *offset_ptr == end_offset) + return ErrorSuccess(); + return createStringError( + errc::invalid_argument, + "address range table at offset 0x%" PRIx64 + " has an invalid tuple (length = 0) at offset 0x%" PRIx64, + Offset, *offset_ptr - tuple_size); + } + ArangeDescriptors.push_back(arangeDescriptor); } 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 @@ -73,6 +73,23 @@ "(4 and 8 supported)"); } +TEST(DWARFDebugArangeSet, UnsupportedSegmentSelectorSize) { + static const char DebugArangesSecRaw[] = + "\x14\x00\x00\x00" // Length + "\x02\x00" // Version + "\x00\x00\x00\x00" // Debug Info Offset + "\x04" // Address Size + "\x04" // Segment Selector Size (not supported) + // No padding + "\x00\x00\x00\x00" // Termination tuple + "\x00\x00\x00\x00" + "\x00\x00\x00\x00"; + ExpectExtractError( + DebugArangesSecRaw, + "non-zero segment selector size in address range table at offset 0x0 " + "is not supported"); +} + TEST(DWARFDebugArangeSet, NoTerminationEntry) { static const char DebugArangesSecRaw[] = "\x14\x00\x00\x00" // Length @@ -90,7 +107,9 @@ } TEST(DWARFDebugArangeSet, ReservedUnitLength) { - static const char DebugArangesSecRaw[] = + // Note: 12 is the minimum length to pass the basic check for the size of + // the section. 1 will be automatically subtracted in ExpectExtractError(). + static const char DebugArangesSecRaw[12 + 1] = "\xf0\xff\xff\xff"; // Reserved unit length value ExpectExtractError( DebugArangesSecRaw, @@ -98,4 +117,76 @@ "of value 0xfffffff0"); } +TEST(DWARFDebugArangeSet, SectionTooShort) { + // Note: 1 will be automatically subtracted in ExpectExtractError(). + static const char DebugArangesSecRaw[11 + 1] = {0}; + ExpectExtractError( + DebugArangesSecRaw, + "section is not large enough to contain an address range table " + "at offset 0x0"); +} + +TEST(DWARFDebugArangeSet, SectionTooShortDWARF64) { + // Note: 1 will be automatically subtracted in ExpectExtractError(). + static const char DebugArangesSecRaw[23 + 1] = + "\xff\xff\xff\xff"; // DWARF64 mark + ExpectExtractError( + DebugArangesSecRaw, + "section is not large enough to contain a DWARF64 address range table " + "at offset 0x0"); +} + +TEST(DWARFDebugArangeSet, NoSpaceForEntries) { + static const char DebugArangesSecRaw[] = + "\x0c\x00\x00\x00" // Length + "\x02\x00" // Version + "\x00\x00\x00\x00" // Debug Info Offset + "\x04" // Address Size + "\x00" // Segment Selector Size + "\x00\x00\x00\x00" // Padding + ; // No entries + ExpectExtractError( + DebugArangesSecRaw, + "address range table at offset 0x0 has an insufficient length " + "to contain any entries"); +} + +TEST(DWARFDebugArangeSet, UnevenLength) { + static const char DebugArangesSecRaw[] = + "\x1b\x00\x00\x00" // Length (not a multiple of tuple size) + "\x02\x00" // Version + "\x00\x00\x00\x00" // Debug Info Offset + "\x04" // Address Size + "\x00" // Segment Selector Size + "\x00\x00\x00\x00" // Padding + "\x00\x00\x00\x00" // Entry: Address + "\x01\x00\x00\x00" // Length + "\x00\x00\x00\x00" // Termination tuple + "\x00\x00\x00\x00"; + ExpectExtractError( + DebugArangesSecRaw, + "address range table at offset 0x0 has length that is not a multiple " + "of the tuple size"); +} + +TEST(DWARFDebugArangeSet, ZeroLengthEntry) { + static const char DebugArangesSecRaw[] = + "\x24\x00\x00\x00" // Length + "\x02\x00" // Version + "\x00\x00\x00\x00" // Debug Info Offset + "\x04" // Address Size + "\x00" // Segment Selector Size + "\x00\x00\x00\x00" // Padding + "\x00\x00\x00\x00" // Entry1: Address + "\x01\x00\x00\x00" // Length + "\x01\x00\x00\x00" // Entry2: Address + "\x00\x00\x00\x00" // Length (invalid) + "\x00\x00\x00\x00" // Termination tuple + "\x00\x00\x00\x00"; + ExpectExtractError( + DebugArangesSecRaw, + "address range table at offset 0x0 has an invalid tuple (length = 0) " + "at offset 0x18"); +} + } // end anonymous namespace