Skip to content

Commit 62a2fef

Browse files
committed
[BOLT] Fix state of MCSymbols in lowering pass
We have mostly harmless data races when running BinaryContext::calculateEmittedSize() in parallel, while performing split function pass. However, it is possible to end up in a state where some MCSymbols are still registered and our clean up failed. This happens rarely but it does happen, and when it happens, it is a difficult to diagnose heisenbug. To avoid this, add a new clean pass to perform a last check on MCSymbols, before they undergo our final emission pass, to verify that they are in a sane state. If we fail to do this, we might resolve some symbols to zero and crash the output binary. Reviewed By: #bolt, Amir Differential Revision: https://reviews.llvm.org/D137984
1 parent 32ab097 commit 62a2fef

File tree

3 files changed

+38
-0
lines changed

3 files changed

+38
-0
lines changed

bolt/include/bolt/Passes/BinaryPasses.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,16 @@ class LowerAnnotations : public BinaryFunctionPass {
213213
void runOnFunctions(BinaryContext &BC) override;
214214
};
215215

216+
/// Clean the state of the MC representation before sending it to emission
217+
class CleanMCState : public BinaryFunctionPass {
218+
public:
219+
explicit CleanMCState(const cl::opt<bool> &PrintPass)
220+
: BinaryFunctionPass(PrintPass) {}
221+
222+
const char *getName() const override { return "clean-mc-state"; }
223+
void runOnFunctions(BinaryContext &BC) override;
224+
};
225+
216226
/// An optimization to simplify conditional tail calls by removing
217227
/// unnecessary branches.
218228
///

bolt/lib/Passes/BinaryPasses.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -626,6 +626,30 @@ void LowerAnnotations::runOnFunctions(BinaryContext &BC) {
626626
BC.MIB->setOffset(*Item.first, Item.second);
627627
}
628628

629+
// Check for dirty state in MCSymbol objects that might be a consequence
630+
// of running calculateEmittedSize() in parallel, during split functions
631+
// pass. If an inconsistent state is found (symbol already registered or
632+
// already defined), clean it.
633+
void CleanMCState::runOnFunctions(BinaryContext &BC) {
634+
MCContext &Ctx = *BC.Ctx;
635+
for (const auto &SymMapEntry : Ctx.getSymbols()) {
636+
const MCSymbol *S = SymMapEntry.second;
637+
if (S->isDefined()) {
638+
LLVM_DEBUG(dbgs() << "BOLT-DEBUG: Symbol \"" << S->getName()
639+
<< "\" is already defined\n");
640+
const_cast<MCSymbol *>(S)->setUndefined();
641+
}
642+
if (S->isRegistered()) {
643+
LLVM_DEBUG(dbgs() << "BOLT-DEBUG: Symbol \"" << S->getName()
644+
<< "\" is already registered\n");
645+
const_cast<MCSymbol *>(S)->setIsRegistered(false);
646+
}
647+
LLVM_DEBUG(if (S->isVariable()) {
648+
dbgs() << "BOLT-DEBUG: Symbol \"" << S->getName() << "\" is variable\n";
649+
});
650+
}
651+
}
652+
629653
// This peephole fixes jump instructions that jump to another basic
630654
// block with a single jump instruction, e.g.
631655
//

bolt/lib/Rewrite/BinaryPassManager.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,10 @@ void BinaryFunctionPassManager::runAllPasses(BinaryContext &BC) {
488488

489489
Manager.registerPass(std::make_unique<LowerAnnotations>(NeverPrint));
490490

491+
// Check for dirty state of MCSymbols caused by running calculateEmittedSize
492+
// in parallel and restore them
493+
Manager.registerPass(std::make_unique<CleanMCState>(NeverPrint));
494+
491495
Manager.runPasses();
492496
}
493497

0 commit comments

Comments
 (0)