Index: llvm/test/tools/llvm-readobj/ELF/dynamic-malformed.test =================================================================== --- llvm/test/tools/llvm-readobj/ELF/dynamic-malformed.test +++ llvm/test/tools/llvm-readobj/ELF/dynamic-malformed.test @@ -3,9 +3,9 @@ # RUN: yaml2obj %s --docnum=1 -o %t.bad-size # RUN: llvm-readobj --all %t.bad-size 2>&1 \ -# RUN: | FileCheck %s -DFILE=%t.bad-size --implicit-check-not=warning --check-prefix WARN +# RUN: | FileCheck %s -DFILE=%t.bad-size --implicit-check-not=warning: --check-prefix WARN # RUN: llvm-readelf --all %t.bad-size 2>&1 \ -# RUN: | FileCheck %s -DFILE=%t.bad-size --implicit-check-not=warning --check-prefix WARN-GNU +# RUN: | FileCheck %s -DFILE=%t.bad-size --implicit-check-not=warning: --check-prefix WARN-GNU # WARN: warning: '[[FILE]]': invalid PT_DYNAMIC size (0x4){{$}} # WARN: warning: '[[FILE]]': section with index 1 has invalid size (0x4){{$}} @@ -95,47 +95,47 @@ # RUN: llvm-readelf --dynamic-table %t.bad-string 2>&1 | \ # RUN: FileCheck %s --implicit-check-not=warning: --check-prefix BAD-STRING-GNU -DFILE=%t.bad-string -# BAD-STRING-LLVM: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb6, it goes past the end of the table (0xb1) +# BAD-STRING-LLVM: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb6: it goes past the end of the table (0xb1) # BAD-STRING-LLVM: LoadName: # BAD-STRING-LLVM: DynamicSection [ (10 entries) # BAD-STRING-LLVM-NEXT: Tag Type Name/Value # BAD-STRING-LLVM-NEXT: 0x0000000000000005 STRTAB 0x1000 # BAD-STRING-LLVM-NEXT: 0x000000000000000A STRSZ 1 (bytes) -# BAD-STRING-LLVM-NEXT: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb2, it goes past the end of the table (0xb1) +# BAD-STRING-LLVM-NEXT: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb2: it goes past the end of the table (0xb1) # BAD-STRING-LLVM-NEXT: 0x0000000000000001 NEEDED Shared library: [] -# BAD-STRING-LLVM-NEXT: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb3, it goes past the end of the table (0xb1) +# BAD-STRING-LLVM-NEXT: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb3: it goes past the end of the table (0xb1) # BAD-STRING-LLVM-NEXT: 0x000000007FFFFFFF FILTER Filter library: [] -# BAD-STRING-LLVM-NEXT: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb4, it goes past the end of the table (0xb1) +# BAD-STRING-LLVM-NEXT: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb4: it goes past the end of the table (0xb1) # BAD-STRING-LLVM-NEXT: 0x000000007FFFFFFD AUXILIARY Auxiliary library: [] -# BAD-STRING-LLVM-NEXT: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb5, it goes past the end of the table (0xb1) +# BAD-STRING-LLVM-NEXT: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb5: it goes past the end of the table (0xb1) # BAD-STRING-LLVM-NEXT: 0x000000007FFFFFFE USED Not needed object: [] ## Note: there is no "string table at offset 0xb0..." warning here, because it was printed earlier. # BAD-STRING-LLVM-NEXT: 0x000000000000000E SONAME Library soname: [] -# BAD-STRING-LLVM-NEXT: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb7, it goes past the end of the table (0xb1) +# BAD-STRING-LLVM-NEXT: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb7: it goes past the end of the table (0xb1) # BAD-STRING-LLVM-NEXT: 0x000000000000000F RPATH Library rpath: [] -# BAD-STRING-LLVM-NEXT: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb8, it goes past the end of the table (0xb1) +# BAD-STRING-LLVM-NEXT: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb8: it goes past the end of the table (0xb1) # BAD-STRING-LLVM-NEXT: 0x000000000000001D RUNPATH Library runpath: [] # BAD-STRING-LLVM-NEXT: 0x0000000000000000 NULL 0x0 # BAD-STRING-LLVM-NEXT: ] -# BAD-STRING-GNU: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb6, it goes past the end of the table (0xb1) +# BAD-STRING-GNU: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb6: it goes past the end of the table (0xb1) # BAD-STRING-GNU-NEXT: Dynamic section at offset 0xb1 contains 10 entries: # BAD-STRING-GNU-NEXT: Tag Type Name/Value # BAD-STRING-GNU-NEXT: 0x0000000000000005 (STRTAB) 0x1000 # BAD-STRING-GNU-NEXT: 0x000000000000000a (STRSZ) 1 (bytes) -# BAD-STRING-GNU-NEXT: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb2, it goes past the end of the table (0xb1) +# BAD-STRING-GNU-NEXT: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb2: it goes past the end of the table (0xb1) # BAD-STRING-GNU-NEXT: 0x0000000000000001 (NEEDED) Shared library: [] -# BAD-STRING-GNU-NEXT: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb3, it goes past the end of the table (0xb1) +# BAD-STRING-GNU-NEXT: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb3: it goes past the end of the table (0xb1) # BAD-STRING-GNU-NEXT: 0x000000007fffffff (FILTER) Filter library: [] -# BAD-STRING-GNU-NEXT: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb4, it goes past the end of the table (0xb1) +# BAD-STRING-GNU-NEXT: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb4: it goes past the end of the table (0xb1) # BAD-STRING-GNU-NEXT: 0x000000007ffffffd (AUXILIARY) Auxiliary library: [] -# BAD-STRING-GNU-NEXT: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb5, it goes past the end of the table (0xb1) +# BAD-STRING-GNU-NEXT: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb5: it goes past the end of the table (0xb1) # BAD-STRING-GNU-NEXT: 0x000000007ffffffe (USED) Not needed object: [] ## Note: there is no "string table at offset 0xb6..." warning here, because it was printed earlier. # BAD-STRING-GNU-NEXT: 0x000000000000000e (SONAME) Library soname: [] -# BAD-STRING-GNU-NEXT: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb7, it goes past the end of the table (0xb1) +# BAD-STRING-GNU-NEXT: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb7: it goes past the end of the table (0xb1) # BAD-STRING-GNU-NEXT: 0x000000000000000f (RPATH) Library rpath: [] -# BAD-STRING-GNU-NEXT: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb8, it goes past the end of the table (0xb1) +# BAD-STRING-GNU-NEXT: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb8: it goes past the end of the table (0xb1) # BAD-STRING-GNU-NEXT: 0x000000000000001d (RUNPATH) Library runpath: [] # BAD-STRING-GNU-NEXT: 0x0000000000000000 (NULL) 0x0 @@ -279,3 +279,130 @@ VAddr: 0x1000 Sections: - Section: .dynamic + +## Check how we handle cases when the dynamic string table is not null-terminated. + +## Case A: the value of the DT_STRSZ tag is equal to the size of +## the not null-terminated dynamic string table. +# RUN: yaml2obj %s -DSTRSZ=7 --docnum=6 -o %t6 +# RUN: llvm-readobj --dynamic-table %t6 2>&1 | \ +# RUN: FileCheck %s -DFILE=%t6 --implicit-check-not=warning: --check-prefixes=NOT-TERMINATED,NOT-TERMINATED-GREQ +# RUN: llvm-readelf --dynamic-table %t6 2>&1 | \ +# RUN: FileCheck %s -DFILE=%t6 --implicit-check-not=warning: --check-prefixes=NOT-TERMINATED,NOT-TERMINATED-GREQ + +## Case B: the value of the DT_STRSZ tag is less than the size of +## the not null-terminated dynamic string table. +# RUN: yaml2obj %s -DSTRSZ=6 --docnum=6 -o %t7 +# RUN: llvm-readobj --dynamic-table %t7 2>&1 | \ +# RUN: FileCheck %s -DFILE=%t7 --implicit-check-not=warning: --check-prefixes=NOT-TERMINATED,NOT-TERMINATED-LESS +# RUN: llvm-readelf --dynamic-table %t7 2>&1 | \ +# RUN: FileCheck %s -DFILE=%t7 --implicit-check-not=warning: --check-prefixes=NOT-TERMINATED,NOT-TERMINATED-LESS + +## Case C: the value of the DT_STRSZ tag is one byte larger than the size of +## the not null-terminated dynamic string table. +# RUN: yaml2obj %s -DSTRSZ=8 --docnum=6 -o %t8 +# RUN: llvm-readobj --dynamic-table %t8 2>&1 | \ +# RUN: FileCheck %s -DFILE=%t8 --implicit-check-not=warning: --check-prefixes=NOT-TERMINATED,NOT-TERMINATED-GREQ +# RUN: llvm-readelf --dynamic-table %t8 2>&1 | \ +# RUN: FileCheck %s -DFILE=%t8 --implicit-check-not=warning: --check-prefixes=NOT-TERMINATED,NOT-TERMINATED-GREQ + +# NOT-TERMINATED: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb4: the string table is not null-terminated +# NOT-TERMINATED: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb0: the string table is not null-terminated +# NOT-TERMINATED-NEXT: {{[(]?}}NEEDED{{[)]?}} Shared library: [] +# NOT-TERMINATED-NEXT: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb1: the string table is not null-terminated +# NOT-TERMINATED-NEXT: {{[(]?}}FILTER{{[)]?}} Filter library: [] +# NOT-TERMINATED-NEXT: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb2: the string table is not null-terminated +# NOT-TERMINATED-NEXT: {{[(]?}}AUXILIARY{{[)]?}} Auxiliary library: [] +# NOT-TERMINATED-NEXT: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb3: the string table is not null-terminated +# NOT-TERMINATED-NEXT: {{[(]?}}USED{{[)]?}} Not needed object: [] +# NOT-TERMINATED-NEXT: {{[(]?}}SONAME{{[)]?}} Library soname: [] +# NOT-TERMINATED-NEXT: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb5: the string table is not null-terminated +# NOT-TERMINATED-NEXT: {{[(]?}}RPATH{{[)]?}} Library rpath: [] +# NOT-TERMINATED-GREQ-NEXT: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb6: the string table is not null-terminated +# NOT-TERMINATED-LESS-NEXT: warning: '[[FILE]]': string table at offset 0xb0: unable to read the string at 0xb6: it goes past the end of the table (0xb6) +# NOT-TERMINATED-NEXT: {{[(]?}}RUNPATH{{[)]?}} Library runpath: [] +# NOT-TERMINATED-NEXT: {{[(]?}}NULL{{[)]?}} 0x0 + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +Sections: + - Name: .dynstr + Type: SHT_STRTAB + Address: 0x1000 + Content: '746573742e736f' ## "test.so", not null terminated. + - Type: Fill + Pattern: "61626300" ## 'a', 'b', 'c', '\0'. + Size: "4" + - Name: .dynamic + Type: SHT_DYNAMIC + Address: 0x1100 + Entries: + - Tag: DT_STRTAB + Value: 0x1000 + - Tag: DT_STRSZ + Value: [[STRSZ]] + - Tag: DT_NEEDED + Value: 0 + - Tag: DT_FILTER + Value: 1 + - Tag: DT_AUXILIARY + Value: 2 + - Tag: DT_USED + Value: 3 + - Tag: DT_SONAME + Value: 4 + - Tag: DT_RPATH + Value: 5 + - Tag: DT_RUNPATH + Value: 6 + - Tag: DT_NULL + Value: 0 +ProgramHeaders: + - Type: PT_LOAD + VAddr: 0x1000 + Sections: + - Section: .dynstr + - Section: .dynamic + - Type: PT_DYNAMIC + VAddr: 0x1100 + Sections: + - Section: .dynamic + +## Document we do when the dynamic string table ends past the end of the file. Check we do not crash. + +## Case A: the value of DT_STRSZ tag is set so that the string table ends right before the EOF. +# RUN: yaml2obj %s -DSTRSZ=0x210 --docnum=6 -o %t9.1 +# RUN: llvm-readobj --dynamic-table %t9.1 | \ +# RUN: FileCheck %s --implicit-check-not=warning: --check-prefix=BEFORE-THE-EOF +# RUN: llvm-readelf --dynamic-table %t9.1 | \ +# RUN: FileCheck %s --implicit-check-not=warning: --check-prefix=BEFORE-THE-EOF + +## Note: strings are dumped because the file ends with the zero byte. Code reads the data +## in [DT_STRTAB, DT_STRTAB + DT_STRSZ] range as a normal null-terminated string table. +# BEFORE-THE-EOF: {{[(]?}}NEEDED{{[)]?}} Shared library: [test.soabc] +# BEFORE-THE-EOF-NEXT: {{[(]?}}FILTER{{[)]?}} Filter library: [est.soabc] +# BEFORE-THE-EOF-NEXT: {{[(]?}}AUXILIARY{{[)]?}} Auxiliary library: [st.soabc] +# BEFORE-THE-EOF-NEXT: {{[(]?}}USED{{[)]?}} Not needed object: [t.soabc] +# BEFORE-THE-EOF-NEXT: {{[(]?}}SONAME{{[)]?}} Library soname: [.soabc] +# BEFORE-THE-EOF-NEXT: {{[(]?}}RPATH{{[)]?}} Library rpath: [soabc] +# BEFORE-THE-EOF-NEXT: {{[(]?}}RUNPATH{{[)]?}} Library runpath: [oabc] +# BEFORE-THE-EOF-NEXT: {{[(]?}}NULL{{[)]?}} 0x0 + +## Case B: the value of DT_STRSZ tag is set so that the string table goes 1 byte past the EOF. +# RUN: yaml2obj %s -DSTRSZ=0x211 --docnum=6 -o %t9.2 +# RUN: llvm-readobj --dynamic-table %t9.2 2>&1 | FileCheck %s -DFILE=%t9.2 --check-prefix=PAST-THE-EOF +# RUN: llvm-readelf --dynamic-table %t9.2 2>&1 | FileCheck %s -DFILE=%t9.2 --check-prefix=PAST-THE-EOF + +# PAST-THE-EOF: warning: '[[FILE]]': string table at offset 0xb0 with size 0x211 goes past the end of the file (0x2c0) +# PAST-THE-EOF: {{[(]?}}NEEDED{{[)]?}} Shared library: [] +# PAST-THE-EOF-NEXT: {{[(]?}}FILTER{{[)]?}} Filter library: [] +# PAST-THE-EOF-NEXT: {{[(]?}}AUXILIARY{{[)]?}} Auxiliary library: [] +# PAST-THE-EOF-NEXT: {{[(]?}}USED{{[)]?}} Not needed object: [] +# PAST-THE-EOF-NEXT: {{[(]?}}SONAME{{[)]?}} Library soname: [] +# PAST-THE-EOF-NEXT: {{[(]?}}RPATH{{[)]?}} Library rpath: [] +# PAST-THE-EOF-NEXT: {{[(]?}}RUNPATH{{[)]?}} Library runpath: [] +# PAST-THE-EOF-NEXT: {{[(]?}}NULL{{[)]?}} 0x0 Index: llvm/test/tools/llvm-readobj/ELF/loadname.test =================================================================== --- llvm/test/tools/llvm-readobj/ELF/loadname.test +++ llvm/test/tools/llvm-readobj/ELF/loadname.test @@ -14,7 +14,7 @@ # GNU: Dynamic section at offset 0x80 contains 4 entries: # GNU-NEXT: Tag Type Name/Value # GNU-NEXT: 0x0000000000000005 (STRTAB) 0x0 -# GNU-NEXT: 0x000000000000000a (STRSZ) 7 (bytes) +# GNU-NEXT: 0x000000000000000a (STRSZ) 8 (bytes) # GNU-NEXT: 0x000000000000000e (SONAME) Library soname: [test.so] # GNU-NEXT: 0x0000000000000000 (NULL) 0x0 @@ -37,7 +37,7 @@ - Tag: DT_STRTAB Value: [[DTSTRTABVAL]] - Tag: DT_STRSZ - Value: 0x0000000000000007 + Value: 0x0000000000000008 - Tag: DT_SONAME Value: 0x0000000000000000 - Tag: DT_NULL Index: llvm/test/tools/llvm-readobj/ELF/needed-libs.test =================================================================== --- llvm/test/tools/llvm-readobj/ELF/needed-libs.test +++ llvm/test/tools/llvm-readobj/ELF/needed-libs.test @@ -10,8 +10,8 @@ ## Document that we also sort error entries. # NEEDED-LIBS:{{^}}NeededLibraries [{{$}} -# NEEDED-LIBS-NEXT: warning: '[[FILE]]': string table at offset 0x78: unable to read the string at 0x9999a11, it goes past the end of the table (0x85){{$}} -# NEEDED-LIBS-NEXT: warning: '[[FILE]]': string table at offset 0x78: unable to read the string at 0x1111189, it goes past the end of the table (0x85){{$}} +# NEEDED-LIBS-NEXT: warning: '[[FILE]]': string table at offset 0x78: unable to read the string at 0x9999a11: it goes past the end of the table (0x85){{$}} +# NEEDED-LIBS-NEXT: warning: '[[FILE]]': string table at offset 0x78: unable to read the string at 0x1111189: it goes past the end of the table (0x85){{$}} # NEEDED-LIBS-NEXT:{{^}} {{$}} # NEEDED-LIBS-NEXT:{{^}} {{$}} # NEEDED-LIBS-NEXT:{{^}} aaa{{$}} @@ -63,11 +63,11 @@ # RUN: llvm-readelf --needed-libs %t2 2>&1 | \ # RUN: FileCheck %s -DFILE=%t2 --implicit-check-not=warning: --check-prefix=EMPTY-DYNSTR -# EMPTY-DYNSTR: warning: '[[FILE]]': string table at offset 0x78: unable to read the string at 0x78, it goes past the end of the table (0x78) +# EMPTY-DYNSTR: warning: '[[FILE]]': string table at offset 0x78: unable to read the string at 0x78: it goes past the end of the table (0x78) # EMPTY-DYNSTR-LLVM: LoadName: # EMPTY-DYNSTR: NeededLibraries [ -# EMPTY-DYNSTR-NEXT: warning: '[[FILE]]': string table at offset 0x78: unable to read the string at 0x79, it goes past the end of the table (0x78) -# EMPTY-DYNSTR-NEXT: warning: '[[FILE]]': string table at offset 0x78: unable to read the string at 0x7a, it goes past the end of the table (0x78) +# EMPTY-DYNSTR-NEXT: warning: '[[FILE]]': string table at offset 0x78: unable to read the string at 0x79: it goes past the end of the table (0x78) +# EMPTY-DYNSTR-NEXT: warning: '[[FILE]]': string table at offset 0x78: unable to read the string at 0x7a: it goes past the end of the table (0x78) # EMPTY-DYNSTR-NEXT: # EMPTY-DYNSTR-NEXT: # EMPTY-DYNSTR-NEXT: ] Index: llvm/tools/llvm-readobj/ELFDumper.cpp =================================================================== --- llvm/tools/llvm-readobj/ELFDumper.cpp +++ llvm/tools/llvm-readobj/ELFDumper.cpp @@ -2558,24 +2558,41 @@ template StringRef ELFDumper::getDynamicString(uint64_t Value) const { - auto WarnAndReturn = [this](const Twine &Msg) { - reportUniqueWarning(createError(Msg)); + if (DynamicStringTable.empty() && !DynamicStringTable.data()) { + reportUniqueWarning(createError("string table was not found")); return ""; - }; - - if (DynamicStringTable.empty() && !DynamicStringTable.data()) - return WarnAndReturn("string table was not found"); + } - if (Value < DynamicStringTable.size()) - return DynamicStringTable.data() + Value; + auto WarnAndReturn = [this](const Twine &Msg, uint64_t Offset) { + reportUniqueWarning(createError("string table at offset 0x" + + Twine::utohexstr(Offset) + Msg)); + return ""; + }; + const uint64_t FileSize = ObjF->getELFFile()->getBufSize(); const uint64_t Offset = (const uint8_t *)DynamicStringTable.data() - ObjF->getELFFile()->base(); - return WarnAndReturn( - "string table at offset 0x" + Twine::utohexstr(Offset) + - ": unable to read the string at 0x" + Twine::utohexstr(Offset + Value) + - ", it goes past the end of the table (0x" + - Twine::utohexstr(Offset + DynamicStringTable.size()) + ")"); + if (DynamicStringTable.size() > FileSize - Offset) + return WarnAndReturn(" with size 0x" + + Twine::utohexstr(DynamicStringTable.size()) + + " goes past the end of the file (0x" + + Twine::utohexstr(FileSize) + ")", + Offset); + + if (Value >= DynamicStringTable.size()) + return WarnAndReturn( + ": unable to read the string at 0x" + Twine::utohexstr(Offset + Value) + + ": it goes past the end of the table (0x" + + Twine::utohexstr(Offset + DynamicStringTable.size()) + ")", + Offset); + + if (DynamicStringTable.back() != '\0') + return WarnAndReturn(": unable to read the string at 0x" + + Twine::utohexstr(Offset + Value) + + ": the string table is not null-terminated", + Offset); + + return DynamicStringTable.data() + Value; } template void ELFDumper::printUnwindInfo() {