Skip to content

Commit ea12c1f

Browse files
authored
[Asan] Add "funclet" OpBundle to generated runtime calls if required by EH personality (#82533)
Previously, runtime calls introduced by ASan instrumentation into EH pads were missing the funclet token expected by WinEHPrepare. WinEHPrepare would then identify the containing BB as invalid and discard it, causing invalid code generation that most likely crashes. Also fixed localescape test, switching its EH personality to match code without funclets. This PR is based on the Phabricator patch https://reviews.llvm.org/D143108 Fixes #64990
1 parent dbca8aa commit ea12c1f

File tree

4 files changed

+402
-209
lines changed

4 files changed

+402
-209
lines changed
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Repro for the issue #64990: Asan with Windows EH generates __asan_xxx runtime calls without required funclet tokens
2+
// RUN: %clang_cl_asan %Od %s -EHsc %Fe%t
3+
// RUN: not %run %t 2>&1 | FileCheck %s
4+
5+
char buff1[6] = "hello";
6+
char buff2[6] = "hello";
7+
8+
int main(int argc, char **argv) {
9+
try {
10+
throw 1;
11+
} catch (...) {
12+
// Make asan generate call to __asan_memcpy inside the EH pad.
13+
__builtin_memcpy(buff1, buff2 + 3, 6);
14+
}
15+
return 0;
16+
}
17+
18+
// CHECK: SUMMARY: AddressSanitizer: global-buffer-overflow {{.*}} in __asan_memcpy

llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp

Lines changed: 56 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
#include "llvm/IR/DebugInfoMetadata.h"
4444
#include "llvm/IR/DebugLoc.h"
4545
#include "llvm/IR/DerivedTypes.h"
46+
#include "llvm/IR/EHPersonalities.h"
4647
#include "llvm/IR/Function.h"
4748
#include "llvm/IR/GlobalAlias.h"
4849
#include "llvm/IR/GlobalValue.h"
@@ -643,21 +644,70 @@ static uint64_t GetCtorAndDtorPriority(Triple &TargetTriple) {
643644

644645
namespace {
645646
/// Helper RAII class to post-process inserted asan runtime calls during a
646-
/// pass on a single Function. This is a no-op implementation, for a first NFC
647-
/// commit. Coming up: detect and add "funclet" opBundle to function calls that
648-
/// need them.
647+
/// pass on a single Function. Upon end of scope, detects and applies the
648+
/// required funclet OpBundle.
649649
class RuntimeCallInserter {
650650
Function *OwnerFn = nullptr;
651+
bool TrackInsertedCalls = false;
652+
SmallVector<CallInst *> InsertedCalls;
651653

652654
public:
653-
RuntimeCallInserter(Function &Fn) : OwnerFn(&Fn) {}
655+
RuntimeCallInserter(Function &Fn) : OwnerFn(&Fn) {
656+
if (Fn.hasPersonalityFn()) {
657+
auto Personality = classifyEHPersonality(Fn.getPersonalityFn());
658+
if (isScopedEHPersonality(Personality))
659+
TrackInsertedCalls = true;
660+
}
661+
}
662+
663+
~RuntimeCallInserter() {
664+
if (InsertedCalls.empty())
665+
return;
666+
assert(TrackInsertedCalls && "Calls were wrongly tracked");
667+
668+
DenseMap<BasicBlock *, ColorVector> BlockColors = colorEHFunclets(*OwnerFn);
669+
for (CallInst *CI : InsertedCalls) {
670+
BasicBlock *BB = CI->getParent();
671+
assert(BB && "Instruction doesn't belong to a BasicBlock");
672+
assert(BB->getParent() == OwnerFn &&
673+
"Instruction doesn't belong to the expected Function!");
674+
675+
ColorVector &Colors = BlockColors[BB];
676+
// funclet opbundles are only valid in monochromatic BBs.
677+
// Note that unreachable BBs are seen as colorless by colorEHFunclets()
678+
// and will be DCE'ed later.
679+
if (Colors.empty())
680+
continue;
681+
if (Colors.size() != 1) {
682+
OwnerFn->getContext().emitError(
683+
"Instruction's BasicBlock is not monochromatic");
684+
continue;
685+
}
686+
687+
BasicBlock *Color = Colors.front();
688+
Instruction *EHPad = Color->getFirstNonPHI();
689+
690+
if (EHPad && EHPad->isEHPad()) {
691+
// Replace CI with a clone with an added funclet OperandBundle
692+
OperandBundleDef OB("funclet", EHPad);
693+
auto *NewCall =
694+
CallBase::addOperandBundle(CI, LLVMContext::OB_funclet, OB, CI);
695+
NewCall->copyMetadata(*CI);
696+
CI->replaceAllUsesWith(NewCall);
697+
CI->eraseFromParent();
698+
}
699+
}
700+
}
654701

655702
CallInst *createRuntimeCall(IRBuilder<> &IRB, FunctionCallee Callee,
656703
ArrayRef<Value *> Args = {},
657704
const Twine &Name = "") {
658705
assert(IRB.GetInsertBlock()->getParent() == OwnerFn);
659-
(void)OwnerFn;
660-
return IRB.CreateCall(Callee, Args, Name, nullptr);
706+
707+
CallInst *Inst = IRB.CreateCall(Callee, Args, Name, nullptr);
708+
if (TrackInsertedCalls)
709+
InsertedCalls.push_back(Inst);
710+
return Inst;
661711
}
662712
};
663713

0 commit comments

Comments
 (0)