diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp --- a/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp @@ -155,25 +155,36 @@ } // Parse v2-v4 directory and file tables. -static void +static Error parseV2DirFileTables(const DWARFDataExtractor &DebugLineData, uint64_t *OffsetPtr, uint64_t EndPrologueOffset, DWARFDebugLine::ContentTypeTracker &ContentTypes, std::vector &IncludeDirectories, std::vector &FileNames) { + bool IncludeDirsTerminated = false; while (*OffsetPtr < EndPrologueOffset) { StringRef S = DebugLineData.getCStrRef(OffsetPtr); - if (S.empty()) + if (S.empty()) { + IncludeDirsTerminated = true; break; + } DWARFFormValue Dir = DWARFFormValue::createFromPValue(dwarf::DW_FORM_string, S.data()); IncludeDirectories.push_back(Dir); } + if (!IncludeDirsTerminated) + return createStringError(errc::invalid_argument, + "include directories table was not terminated " + "before the end of the prologue"); + + bool FileNamesTerminated = false; while (*OffsetPtr < EndPrologueOffset) { StringRef Name = DebugLineData.getCStrRef(OffsetPtr); - if (Name.empty()) + if (Name.empty()) { + FileNamesTerminated = true; break; + } DWARFDebugLine::FileNameEntry FileEntry; FileEntry.Name = DWARFFormValue::createFromPValue(dwarf::DW_FORM_string, Name.data()); @@ -185,6 +196,13 @@ ContentTypes.HasModTime = true; ContentTypes.HasLength = true; + + if (!FileNamesTerminated) + return createStringError( + errc::invalid_argument, + "file names table was not terminated before the end of the prologue"); + + return Error::success(); } // Parse v5 directory/file entry content descriptions. @@ -361,27 +379,30 @@ StandardOpcodeLengths.push_back(OpLen); } + auto ReportInvalidDirFileTable = [&](Error E) { + RecoverableErrorCallback(joinErrors( + createStringError( + errc::invalid_argument, + "parsing line table prologue at 0x%8.8" PRIx64 + " found an invalid directory or file table description at" + " 0x%8.8" PRIx64, + PrologueOffset, *OffsetPtr), + std::move(E))); + // Skip to the end of the prologue, since the chances are that the parser + // did not read the whole table. This prevents the length check below from + // executing. + if (*OffsetPtr < EndPrologueOffset) + *OffsetPtr = EndPrologueOffset; + }; if (getVersion() >= 5) { if (Error E = parseV5DirFileTables(DebugLineData, OffsetPtr, FormParams, Ctx, U, - ContentTypes, IncludeDirectories, FileNames)) { - RecoverableErrorCallback(joinErrors( - createStringError( - errc::invalid_argument, - "parsing line table prologue at 0x%8.8" PRIx64 - " found an invalid directory or file table description at" - " 0x%8.8" PRIx64, - PrologueOffset, *OffsetPtr), - std::move(E))); - // Skip to the end of the prologue, since the chances are that the parser - // did not read the whole table. This prevents the length check below from - // executing. - if (*OffsetPtr < EndPrologueOffset) - *OffsetPtr = EndPrologueOffset; - } - } else - parseV2DirFileTables(DebugLineData, OffsetPtr, EndPrologueOffset, - ContentTypes, IncludeDirectories, FileNames); + ContentTypes, IncludeDirectories, FileNames)) + ReportInvalidDirFileTable(std::move(E)); + } else if (Error E = parseV2DirFileTables(DebugLineData, OffsetPtr, + EndPrologueOffset, ContentTypes, + IncludeDirectories, FileNames)) + ReportInvalidDirFileTable(std::move(E)); if (*OffsetPtr != EndPrologueOffset) { RecoverableErrorCallback(createStringError( diff --git a/llvm/test/tools/llvm-dwarfdump/X86/Inputs/debug_line_malformed.s b/llvm/test/tools/llvm-dwarfdump/X86/Inputs/debug_line_malformed.s --- a/llvm/test/tools/llvm-dwarfdump/X86/Inputs/debug_line_malformed.s +++ b/llvm/test/tools/llvm-dwarfdump/X86/Inputs/debug_line_malformed.s @@ -83,8 +83,6 @@ .Lprologue_short_prologue_end: .byte 6 # Read as part of the prologue, # then later again as DW_LNS_negate_stmt. -# FIXME: There should be an additional 0 byte here, but the file name parsing -# code does not recognise a missing null terminator. # Header end .byte 0, 9, 2 # DW_LNE_set_address .quad 0x1122334455667788 @@ -423,6 +421,49 @@ .byte 0, 1, 1 # DW_LNE_end_sequence .Linvalid_dir_form_end0: +# V4 table with unterminated include directory table. +.long .Lunterminated_include_end - .Lunterminated_include_start # unit length +.Lunterminated_include_start: +.short 4 # version +.long .Lunterminated_include_prologue_end-.Lunterminated_include_prologue_start # Length of Prologue +.Lunterminated_include_prologue_start: +.byte 1 # Minimum Instruction Length +.byte 1 # Maximum Operations per Instruction +.byte 1 # Default is_stmt +.byte -5 # Line Base +.byte 14 # Line Range +.byte 13 # Opcode Base +.byte 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 # Standard Opcode Lengths +.asciz "dir1" # Include table +.Lunterminated_include_prologue_end: +.byte 0, 9, 2 # DW_LNE_set_address +.quad 0xabcdef0123456789 +.byte 0, 1, 1 # DW_LNE_end_sequence +.Lunterminated_include_end: + +# V4 table with unterminated file name table. +.long .Lunterminated_files_end - .Lunterminated_files_start # unit length +.Lunterminated_files_start: +.short 4 # version +.long .Lunterminated_files_prologue_end-.Lunterminated_files_prologue_start # Length of Prologue +.Lunterminated_files_prologue_start: +.byte 1 # Minimum Instruction Length +.byte 1 # Maximum Operations per Instruction +.byte 1 # Default is_stmt +.byte -5 # Line Base +.byte 14 # Line Range +.byte 13 # Opcode Base +.byte 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 # Standard Opcode Lengths +.asciz "dir1" # Include table +.byte 0 +.asciz "foo.c" # File table +.byte 1, 2, 3 +.Lunterminated_files_prologue_end: +.byte 0, 9, 2 # DW_LNE_set_address +.quad 0xababcdcdefef0909 +.byte 0, 1, 1 # DW_LNE_end_sequence +.Lunterminated_files_end: + # Trailing good section. .long .Lunit_good_end - .Lunit_good_start # Length of Unit (DWARF-32 format) .Lunit_good_start: diff --git a/llvm/test/tools/llvm-dwarfdump/X86/debug_line_invalid.test b/llvm/test/tools/llvm-dwarfdump/X86/debug_line_invalid.test --- a/llvm/test/tools/llvm-dwarfdump/X86/debug_line_invalid.test +++ b/llvm/test/tools/llvm-dwarfdump/X86/debug_line_invalid.test @@ -36,7 +36,7 @@ # RUN: FileCheck %s --input-file=%t-malformed-off-first.err --check-prefix=ALL ## Don't stop looking for the later unit if non-fatal issues are found. -# RUN: llvm-dwarfdump -debug-line=0x332 %t-malformed.o 2> %t-malformed-off-last.err \ +# RUN: llvm-dwarfdump -debug-line=0x39a %t-malformed.o 2> %t-malformed-off-last.err \ # RUN: | FileCheck %s --check-prefix=LAST --implicit-check-not='debug_line[{{.*}}]' # RUN: FileCheck %s --input-file=%t-malformed-off-last.err --check-prefix=ALL @@ -158,7 +158,25 @@ # NONFATAL-NOT: file_names # NONFATAL: 0xaaaabbbbccccdddd {{.*}} is_stmt end_sequence -# LAST: debug_line[0x00000332] +## V4 table with unterminated include directory table. +# NONFATAL: debug_line[0x00000332] +# NONFATAL-NEXT: Line table prologue +# NONFATAL: include_directories[ 1] = "dir1" +# NONFATAL-NOT: file_names +# NONFATAL: 0xabcdef0123456789 {{.*}} is_stmt end_sequence + +## V4 table with unterminated file name table. +# NONFATAL: debug_line[0x00000361] +# NONFATAL-NEXT: Line table prologue +# NONFATAL: file_names[ 1]: +# NONFATAL-NEXT: name: "foo.c" +# NONFATAL-NEXT: dir_index: 1 +# NONFATAL-NEXT: mod_time: 0x00000002 +# NONFATAL-NEXT: length: 0x00000003 +# NONFATAL-NOT: file_names +# NONFATAL: 0xababcdcdefef0909 {{.*}} is_stmt end_sequence + +# LAST: debug_line[0x0000039a] # LAST: 0x00000000cafebabe {{.*}} end_sequence # RESERVED: warning: parsing line table prologue at offset 0x00000048 unsupported reserved unit length found of value 0xfffffffe @@ -168,6 +186,8 @@ # ALL-NEXT: warning: parsing line table prologue at offset 0x0000004e found unsupported version 0x01 # ALL-NEXT: warning: parsing line table prologue at 0x00000054 found an invalid directory or file table description at 0x00000073 # ALL-NEXT: warning: failed to parse entry content descriptions because no path was found +# ALL-NEXT: warning: parsing line table prologue at 0x00000081 found an invalid directory or file table description at 0x000000ba +# ALL-NEXT: warning: file names table was not terminated before the end of the prologue # ALL-NEXT: warning: parsing line table prologue at 0x00000081 should have ended at 0x000000b9 but it ended at 0x000000ba # ALL-NEXT: warning: parsing line table prologue at 0x000000c8 should have ended at 0x00000103 but it ended at 0x00000102 # OTHER-NEXT: warning: unexpected line op length at offset 0x00000158 expected 0x02 found 0x01 @@ -183,4 +203,8 @@ # ALL-NEXT: warning: parsing line table prologue at 0x000002ae should have ended at 0x000002d9 but it ended at 0x000002e0 # ALL-NEXT: warning: parsing line table prologue at 0x000002ec found an invalid directory or file table description at 0x00000315 # ALL-NEXT: warning: failed to parse directory entry because skipping the form value failed. +# ALL-NEXT: warning: parsing line table prologue at 0x00000332 found an invalid directory or file table description at 0x00000353 +# ALL-NEXT: warning: include directories table was not terminated before the end of the prologue +# ALL-NEXT: warning: parsing line table prologue at 0x00000361 found an invalid directory or file table description at 0x0000038c +# ALL-NEXT: warning: file names table was not terminated before the end of the prologue # ALL-NOT: warning: