- Section: .hash
- Section: .gnu.hash
- Section: .dynamic
+
+## Check we report a proper warning when the GNU hash table goes past the end of the file.
+
+## Case A: the 'nbuckets' field is set so that the GNU hash table goes past the end of the file.
+## The value of 1 for the NBUCKETS is no-op.
+# RUN: yaml2obj --docnum=6 -D MASKWORDS=4294967295 -D NBUCKETS=1 %s -o %t7
+# RUN: llvm-readelf --elf-hash-histogram %t7 2>&1 | \
+# RUN: FileCheck %s -DFILE=%t7 --check-prefix=ERR5 --implicit-check-not="Histogram"
+
+# ERR5: warning: '[[FILE]]': unable to dump the SHT_GNU_HASH section at 0x78: it goes past the end of the file
+
+## Case B: the 'maskwords' field is set so that the GNU hash table goes past the end of the file.
+## The value of 1 for the MASKWORDS is no-op.
+# RUN: yaml2obj --docnum=6 -D MASKWORDS=1 -D NBUCKETS=4294967295 %s -o %t8
+# RUN: llvm-readelf --elf-hash-histogram %t8 2>&1 | \
+# RUN: FileCheck %s -DFILE=%t8 --check-prefix=ERR5 --implicit-check-not="Histogram"
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_DYN
+ Machine: EM_X86_64
+Sections:
+ - Name: .gnu.hash
+ Type: SHT_GNU_HASH
+ Flags: [ SHF_ALLOC ]
+ Header:
+ SymNdx: 0x0
+ Shift2: 0x0
+## The number of words in the Bloom filter.
+ MaskWords: [[MASKWORDS]]
+## The number of hash buckets.
+ NBuckets: [[NBUCKETS]]
+ BloomFilter: [ 0x0 ]
+ HashBuckets: [ 0x0 ]
+ HashValues: [ 0x0 ]
+ - Name: .dynamic
+ Type: SHT_DYNAMIC
+ Flags: [ SHF_ALLOC ]
+ Link: .dynstr
+ Entries:
+ - Tag: DT_GNU_HASH
+ Value: 0x0
+ - Tag: DT_NULL
+ Value: 0x0
+DynamicSymbols: []
+ProgramHeaders:
+ - Type: PT_LOAD
+ Sections:
+ - Section: .gnu.hash
+ - Section: .dynamic
return true;
}
+template <class ELFT>
+static Error checkGNUHashTable(const ELFFile<ELFT> *Obj,
+ const typename ELFT::GnuHash *GnuHashTable,
+ bool *IsHeaderValid = nullptr) {
+ const uint8_t *TableData = reinterpret_cast<const uint8_t *>(GnuHashTable);
+ assert(TableData >= Obj->base() &&
+ TableData < Obj->base() + Obj->getBufSize() &&
+ "GnuHashTable must always point to a location inside the file");
+
+ uint64_t TableOffset = TableData - Obj->base();
+ if (IsHeaderValid)
+ *IsHeaderValid = TableOffset + /*Header size:*/ 16 < Obj->getBufSize();
+ if (TableOffset + 16 + GnuHashTable->nbuckets * 4 +
+ GnuHashTable->maskwords * sizeof(typename ELFT::Off) >=
+ Obj->getBufSize())
+ return createError("unable to dump the SHT_GNU_HASH "
+ "section at 0x" +
+ Twine::utohexstr(TableOffset) +
+ ": it goes past the end of the file");
+ return Error::success();
+}
+
template <typename ELFT> void ELFDumper<ELFT>::printHashTable() {
DictScope D(W, "HashTable");
if (!HashTable ||
DictScope D(W, "GnuHashTable");
if (!GnuHashTable)
return;
- W.printNumber("Num Buckets", GnuHashTable->nbuckets);
- W.printNumber("First Hashed Symbol Index", GnuHashTable->symndx);
- W.printNumber("Num Mask Words", GnuHashTable->maskwords);
- W.printNumber("Shift Count", GnuHashTable->shift2);
-
- MemoryBufferRef File = Obj->getMemoryBufferRef();
- const char *TableData = reinterpret_cast<const char *>(GnuHashTable);
- assert(TableData >= File.getBufferStart() &&
- TableData < File.getBufferEnd() &&
- "GnuHashTable must always point to a location inside the file");
- uint64_t TableOffset = TableData - File.getBufferStart();
- if (TableOffset +
- /*Header size:*/ 16 + GnuHashTable->nbuckets * 4 +
- GnuHashTable->maskwords * sizeof(typename ELFT::Off) >=
- File.getBufferSize()) {
- reportWarning(createError("unable to dump the SHT_GNU_HASH "
- "section at 0x" +
- Twine::utohexstr(TableOffset) +
- ": it goes past the end of the file"),
- ObjF->getFileName());
+ bool IsHeaderValid;
+ Error Err =
+ checkGNUHashTable<ELFT>(ObjF->getELFFile(), GnuHashTable, &IsHeaderValid);
+ if (IsHeaderValid) {
+ W.printNumber("Num Buckets", GnuHashTable->nbuckets);
+ W.printNumber("First Hashed Symbol Index", GnuHashTable->symndx);
+ W.printNumber("Num Mask Words", GnuHashTable->maskwords);
+ W.printNumber("Shift Count", GnuHashTable->shift2);
+ }
+
+ if (Err) {
+ reportUniqueWarning(std::move(Err));
return;
}
// Print histogram for the .gnu.hash section.
if (const Elf_GnuHash *GnuHashTable = this->dumper()->getGnuHashTable())
- printGnuHashHistogram(*GnuHashTable);
+ if (Error E = checkGNUHashTable<ELFT>(Obj, GnuHashTable))
+ this->reportUniqueWarning(std::move(E));
+ else
+ printGnuHashHistogram(*GnuHashTable);
}
template <class ELFT>