[BOLT] Better check for compiler de-virtualization bug

Summary:
The existing check for compiler de-virtualization bug was not working
when the relocation reference did not fall on a function boundary.
As a result, we were falsely detecting "unmarked object in code".

When running the check, the address could be arbitrary, except it
shouldn't match any existing function. Additionally, check that there's
a proper reference to the de-virtualized callee to avoid false
positives.

(cherry picked from FBD17433887)
This commit is contained in:
Maksim Panchenko 2019-09-17 14:24:31 -07:00
parent e9c6c73bb8
commit c823220116
1 changed files with 27 additions and 13 deletions

View File

@ -2331,6 +2331,33 @@ void RewriteInstance::readRelocations(const SectionRef &Section) {
} }
} }
// Workaround for a member function pointer de-virtualization bug. We check
// if a non-pc-relative relocation in the code is pointing to (fptr - 1).
if (IsToCode && ContainingBF && !Relocation::isPCRelative(RType) &&
(!ReferencedBF || (ReferencedBF->getAddress() != Address))) {
if (const auto *RogueBF = BC->getBinaryFunctionAtAddress(Address + 1)) {
// Do an extra check that the function was referenced previously.
// It's a linear search, but it should rarely happen.
bool Found{false};
for (const auto &RelKV : ContainingBF->Relocations) {
const auto &Rel = RelKV.second;
if (Rel.Symbol == RogueBF->getSymbol() &&
!Relocation::isPCRelative(Rel.Type)) {
Found = true;
break;
}
}
if (Found) {
errs() << "BOLT-WARNING: detected possible compiler "
"de-virtualization bug: -1 addend used with "
"non-pc-relative relocation against function "
<< *RogueBF << " in function " << *ContainingBF << '\n';
continue;
}
}
}
uint64_t RefFunctionOffset = 0; uint64_t RefFunctionOffset = 0;
MCSymbol *ReferencedSymbol = nullptr; MCSymbol *ReferencedSymbol = nullptr;
if (ForceRelocation) { if (ForceRelocation) {
@ -2348,19 +2375,6 @@ void RewriteInstance::readRelocations(const SectionRef &Section) {
if (ReferencedBF->containsAddress(Address, /*UseMaxSize = */true)) { if (ReferencedBF->containsAddress(Address, /*UseMaxSize = */true)) {
RefFunctionOffset = Address - ReferencedBF->getAddress(); RefFunctionOffset = Address - ReferencedBF->getAddress();
if (RefFunctionOffset) { if (RefFunctionOffset) {
// Workaround for member function pointer de-virtualization bug.
// We check if a code non-pc-relative relocation is pointing
// to a (fptr - 1).
if (ContainingBF && !Relocation::isPCRelative(RType)) {
if (const auto *NextBF =
BC->getBinaryFunctionAtAddress(Address + 1)) {
errs() << "BOLT-WARNING: detected possible compiler "
"de-virtualization bug: -1 addend used with "
"non-pc-relative relocation against function "
<< *NextBF << " in function " << *ContainingBF << '\n';
continue;
}
}
ReferencedSymbol = ReferencedSymbol =
ReferencedBF->getOrCreateLocalLabel(Address, ReferencedBF->getOrCreateLocalLabel(Address,
/*CreatePastEnd =*/ true); /*CreatePastEnd =*/ true);