1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-26 12:43:36 +01:00

[llvm-readobj] - Do not crash when GnuHashTable->symndx is greater than the dynamic symbols count.

`Elf_GnuHash_Impl` has the following method:

```
ArrayRef<Elf_Word> values(unsigned DynamicSymCount) const {
  return ArrayRef<Elf_Word>(buckets().end(), DynamicSymCount - symndx);
}
```

When DynamicSymCount is less than symndx we return an array with the huge broken size.
This patch fixes the issue and adds an assert. This assert helped to fix an issue
in one of the test cases.

Differential revision: https://reviews.llvm.org/D81937
This commit is contained in:
Georgii Rymar 2020-06-16 17:05:51 +03:00
parent 4a931ed5b0
commit cdad2ab091
4 changed files with 32 additions and 20 deletions

View File

@ -539,6 +539,7 @@ struct Elf_GnuHash_Impl {
}
ArrayRef<Elf_Word> values(unsigned DynamicSymCount) const {
assert(DynamicSymCount >= symndx);
return ArrayRef<Elf_Word>(buckets().end(), DynamicSymCount - symndx);
}
};

View File

@ -229,15 +229,25 @@ ProgramHeaders:
## which is one larger than the index of the last dynamic symbol.
## For empty tables however, this value is unimportant and can be ignored.
# RUN: yaml2obj --docnum=5 %s -o %t.empty
# RUN: llvm-readobj --gnu-hash-table %t.empty 2>&1 \
# RUN: | FileCheck %s -DFILE=%t.empty --check-prefix=EMPTY --implicit-check-not="warning:"
# RUN: llvm-readelf --gnu-hash-table %t.empty 2>&1 \
# RUN: | FileCheck %s -DFILE=%t.empty --check-prefix=EMPTY --implicit-check-not="warning:"
## Case A: set the index of the first symbol in the dynamic symbol table to
## the number of dynamic symbols.
# RUN: yaml2obj --docnum=5 -DSYMNDX=0x1 %s -o %t.empty.1
# RUN: llvm-readobj --gnu-hash-table %t.empty.1 2>&1 \
# RUN: | FileCheck %s -DFILE=%t.empty.1 -DSYMNDX=1 --check-prefix=EMPTY --implicit-check-not="warning:"
# RUN: llvm-readelf --gnu-hash-table %t.empty.1 2>&1 \
# RUN: | FileCheck %s -DFILE=%t.empty.1 -DSYMNDX=1 --check-prefix=EMPTY --implicit-check-not="warning:"
## Case B: set the index of the first symbol in the dynamic symbol table to
## an arbitrary value that is larger than the number of dynamic symbols.
# RUN: yaml2obj --docnum=5 -DSYMNDX=0x2 %s -o %t.empty.2
# RUN: llvm-readobj --gnu-hash-table %t.empty.2 2>&1 \
# RUN: | FileCheck %s -DFILE=%t.empty.2 -DSYMNDX=2 --check-prefix=EMPTY --implicit-check-not="warning:"
# RUN: llvm-readelf --gnu-hash-table %t.empty.2 2>&1 \
# RUN: | FileCheck %s -DFILE=%t.empty.2 -DSYMNDX=2 --check-prefix=EMPTY --implicit-check-not="warning:"
# EMPTY: GnuHashTable {
# EMPTY-NEXT: Num Buckets: 1
# EMPTY-NEXT: First Hashed Symbol Index: 1
# EMPTY-NEXT: First Hashed Symbol Index: [[SYMNDX]]
# EMPTY-NEXT: Num Mask Words: 1
# EMPTY-NEXT: Shift Count: 0
# EMPTY-NEXT: Bloom Filter: [0x0]
@ -256,7 +266,7 @@ Sections:
Type: SHT_GNU_HASH
Flags: [ SHF_ALLOC ]
Header:
SymNdx: 0x1
SymNdx: [[SYMNDX]]
Shift2: 0x0
BloomFilter: [ 0x0 ]
HashBuckets: [ 0x0 ]

View File

@ -211,8 +211,8 @@ ProgramHeaders:
## Check we dump a histogram for the .gnu.hash table even when the .hash table is skipped.
## Case A: the .hash table has no data to build histogram and it is skipped.
## (NBUCKET == 0x1 is a no-op: it does not change the number of buckets described with the "Bucket" key).
# RUN: yaml2obj --docnum=5 -DNBUCKET=0x1 %s -o %t5.o
## (NBUCKET == 0x2 is a no-op: it does not change the number of buckets described by the "Bucket" key).
# RUN: yaml2obj --docnum=5 -DNBUCKET=0x2 %s -o %t5.o
# RUN: llvm-readelf --elf-hash-histogram %t5.o 2>&1 | \
# RUN: FileCheck %s --check-prefix=GNU-HASH --implicit-check-not="Histogram"
@ -222,8 +222,8 @@ ProgramHeaders:
# RUN: llvm-readelf --elf-hash-histogram %t6.o 2>&1 | \
# RUN: FileCheck %s -DFILE=%t6.o --check-prefixes=WARN,GNU-HASH
# WARN: warning: '[[FILE]]': the hash table at offset 0x78 goes past the end of the file (0x350), nbucket = 4294967295, nchain = 1
# GNU-HASH: Histogram for `.gnu.hash' bucket list length (total of 1 buckets)
# WARN: warning: '[[FILE]]': the hash table at offset 0x78 goes past the end of the file (0x358), nbucket = 4294967295, nchain = 2
# GNU-HASH: Histogram for `.gnu.hash' bucket list length (total of 3 buckets)
--- !ELF
FileHeader:
@ -237,7 +237,7 @@ Sections:
Flags: [ SHF_ALLOC ]
Bucket: [ 0 ]
NBucket: [[NBUCKET]]
Chain: [ 0 ]
Chain: [ 0, 0 ]
- Name: .gnu.hash
Type: SHT_GNU_HASH
Flags: [ SHF_ALLOC ]
@ -254,8 +254,8 @@ Sections:
- Tag: DT_HASH
Value: 0x0
- Tag: DT_GNU_HASH
## sizeof(.hash) == 0x28.
Value: 0x28
## sizeof(.hash) == 0x14.
Value: 0x14
- Tag: DT_NULL
Value: 0x0
DynamicSymbols:

View File

@ -2731,18 +2731,19 @@ getGnuHashTableChains(const typename ELFT::SymRange DynSymTable,
// A normal empty GNU hash table section produced by linker might have
// symndx set to the number of dynamic symbols + 1 (for the zero symbol)
// and have dummy null values in the Bloom filter and in the buckets
// vector. It happens because the value of symndx is not important for
// dynamic loaders when the GNU hash table is empty. They just skip the
// whole object during symbol lookup. In such cases, the symndx value is
// irrelevant and we should not report a warning.
// vector (or no values at all). It happens because the value of symndx is not
// important for dynamic loaders when the GNU hash table is empty. They just
// skip the whole object during symbol lookup. In such cases, the symndx value
// is irrelevant and we should not report a warning.
ArrayRef<typename ELFT::Word> Buckets = GnuHashTable->buckets();
if (!llvm::all_of(Buckets, [](typename ELFT::Word V) { return V == 0; }))
return createError("the first hashed symbol index (" +
Twine(GnuHashTable->symndx) +
") is larger than the number of dynamic symbols (" +
Twine(NumSyms) + ")");
return GnuHashTable->values(NumSyms);
// There is no way to represent an array of (dynamic symbols count - symndx)
// length.
return ArrayRef<typename ELFT::Word>();
}
template <typename ELFT>