[BOLT] Fix intermittent crash with instrumentation

When createInstrumentedIndirectCall() was invoked for tail calls, we
attached annotation instruction twice to the new call instruction.
First in createDirectCall(), and then again while copying over the
metadata operands.

As a result, the annotations were not properly stripped for such calls
before the call to freeAnnotations() in LowerAnnotations pass. That lead
to use-after-free while restoring the offsets with setOffset() call.

Reviewed By: yota9

Differential Revision: https://reviews.llvm.org/D144806
This commit is contained in:
Maksim Panchenko 2023-02-25 18:23:53 -08:00
parent 4364e2429c
commit fb28196a64
4 changed files with 32 additions and 15 deletions

View File

@ -110,6 +110,13 @@ private:
return AnnotationInst;
}
void removeAnnotationInst(MCInst &Inst) const {
assert(getAnnotationInst(Inst) && "Expected annotation instruction.");
Inst.erase(std::prev(Inst.end()));
assert(!getAnnotationInst(Inst) &&
"More than one annotation instruction detected.");
}
void setAnnotationOpValue(MCInst &Inst, unsigned Index, int64_t Value,
AllocatorIdTy AllocatorId = 0) {
MCInst *AnnotationInst = getAnnotationInst(Inst);
@ -163,6 +170,18 @@ protected:
/// MCPlusBuilder classes must use convert/lower/create* interfaces instead.
void setTailCall(MCInst &Inst);
/// Transfer annotations from \p SrcInst to \p DstInst.
void moveAnnotations(MCInst &&SrcInst, MCInst &DstInst) const {
assert(!getAnnotationInst(DstInst) &&
"Destination instruction should not have annotations.");
const MCInst *AnnotationInst = getAnnotationInst(SrcInst);
if (!AnnotationInst)
return;
DstInst.addOperand(MCOperand::createInst(AnnotationInst));
removeAnnotationInst(SrcInst);
}
public:
class InstructionIterator {
public:
@ -1864,9 +1883,8 @@ public:
void stripAnnotations(MCInst &Inst, bool KeepTC = false);
virtual InstructionListType
createInstrumentedIndirectCall(const MCInst &CallInst, bool TailCall,
MCSymbol *HandlerFuncAddr, int CallSiteID,
MCContext *Ctx) {
createInstrumentedIndirectCall(MCInst &&CallInst, MCSymbol *HandlerFuncAddr,
int CallSiteID, MCContext *Ctx) {
llvm_unreachable("not implemented");
return InstructionListType();
}

View File

@ -298,7 +298,8 @@ void MCPlusBuilder::stripAnnotations(MCInst &Inst, bool KeepTC) {
// Preserve TailCall annotation.
auto IsTC = hasAnnotation(Inst, MCAnnotation::kTailCall);
Inst.erase(std::prev(Inst.end()));
removeAnnotationInst(Inst);
if (KeepTC && IsTC)
setTailCall(Inst);
}

View File

@ -215,7 +215,7 @@ void Instrumentation::instrumentIndirectTarget(BinaryBasicBlock &BB,
BinaryContext &BC = FromFunction.getBinaryContext();
bool IsTailCall = BC.MIB->isTailCall(*Iter);
InstructionListType CounterInstrs = BC.MIB->createInstrumentedIndirectCall(
*Iter, IsTailCall,
std::move(*Iter),
IsTailCall ? IndTailCallHandlerExitBBFunction->getSymbol()
: IndCallHandlerExitBBFunction->getSymbol(),
IndCallSiteID, &*BC.Ctx);

View File

@ -3085,8 +3085,7 @@ public:
Inst.addOperand(MCOperand::createReg(X86::NoRegister)); // AddrSegmentReg
}
InstructionListType createInstrumentedIndirectCall(const MCInst &CallInst,
bool TailCall,
InstructionListType createInstrumentedIndirectCall(MCInst &&CallInst,
MCSymbol *HandlerFuncAddr,
int CallSiteID,
MCContext *Ctx) override {
@ -3137,14 +3136,13 @@ public:
createLoadImmediate(Insts.back(), TempReg, CallSiteID);
Insts.emplace_back();
createPushRegister(Insts.back(), TempReg, 8);
Insts.emplace_back();
createDirectCall(Insts.back(), HandlerFuncAddr, Ctx,
/*TailCall=*/TailCall);
// Carry over metadata
for (int I = MCPlus::getNumPrimeOperands(CallInst),
E = CallInst.getNumOperands();
I != E; ++I)
Insts.back().addOperand(CallInst.getOperand(I));
MCInst &NewCallInst = Insts.emplace_back();
createDirectCall(NewCallInst, HandlerFuncAddr, Ctx, isTailCall(CallInst));
// Carry over metadata including tail call marker if present.
stripAnnotations(NewCallInst);
moveAnnotations(std::move(CallInst), NewCallInst);
return Insts;
}