forked from OSchip/llvm-project
[ASAN] Properly deal with musttail calls in ASAN
When address sanitizing a function, stack unpinsoning code is inserted before each ret instruction. However if the ret instruciton is preceded by a musttail call, such transformation broke the musttail call contract and generates invalid IR. This patch fixes the issue by moving the insertion point prior to the musttail call if there is one. Differential Revision: https://reviews.llvm.org/D87777
This commit is contained in:
parent
132aaec4f2
commit
11453740bc
|
@ -556,6 +556,22 @@ static uint64_t GetCtorAndDtorPriority(Triple &TargetTriple) {
|
|||
}
|
||||
}
|
||||
|
||||
// For a ret instruction followed by a musttail call, we cannot insert anything
|
||||
// in between. Instead we use the musttail call instruction as the insertion
|
||||
// point.
|
||||
static Instruction *adjustForMusttailCall(Instruction *I) {
|
||||
ReturnInst *RI = dyn_cast<ReturnInst>(I);
|
||||
if (!RI)
|
||||
return I;
|
||||
Instruction *Prev = RI->getPrevNode();
|
||||
if (BitCastInst *BCI = dyn_cast_or_null<BitCastInst>(Prev))
|
||||
Prev = BCI->getPrevNode();
|
||||
if (CallInst *CI = dyn_cast_or_null<CallInst>(Prev))
|
||||
if (CI->isMustTailCall())
|
||||
return CI;
|
||||
return RI;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
/// Module analysis for getting various metadata about the module.
|
||||
|
@ -999,10 +1015,11 @@ struct FunctionStackPoisoner : public InstVisitor<FunctionStackPoisoner> {
|
|||
|
||||
// Unpoison dynamic allocas redzones.
|
||||
void unpoisonDynamicAllocas() {
|
||||
for (auto &Ret : RetVec)
|
||||
unpoisonDynamicAllocasBeforeInst(Ret, DynamicAllocaLayout);
|
||||
for (Instruction *Ret : RetVec)
|
||||
unpoisonDynamicAllocasBeforeInst(adjustForMusttailCall(Ret),
|
||||
DynamicAllocaLayout);
|
||||
|
||||
for (auto &StackRestoreInst : StackRestoreVec)
|
||||
for (Instruction *StackRestoreInst : StackRestoreVec)
|
||||
unpoisonDynamicAllocasBeforeInst(StackRestoreInst,
|
||||
StackRestoreInst->getOperand(0));
|
||||
}
|
||||
|
@ -3303,8 +3320,9 @@ void FunctionStackPoisoner::processStaticAllocas() {
|
|||
SmallVector<uint8_t, 64> ShadowAfterReturn;
|
||||
|
||||
// (Un)poison the stack before all ret instructions.
|
||||
for (auto Ret : RetVec) {
|
||||
IRBuilder<> IRBRet(Ret);
|
||||
for (Instruction *Ret : RetVec) {
|
||||
Instruction *Adjusted = adjustForMusttailCall(Ret);
|
||||
IRBuilder<> IRBRet(Adjusted);
|
||||
// Mark the current frame as retired.
|
||||
IRBRet.CreateStore(ConstantInt::get(IntptrTy, kRetiredStackFrameMagic),
|
||||
BasePlus0);
|
||||
|
@ -3323,7 +3341,7 @@ void FunctionStackPoisoner::processStaticAllocas() {
|
|||
Value *Cmp =
|
||||
IRBRet.CreateICmpNE(FakeStack, Constant::getNullValue(IntptrTy));
|
||||
Instruction *ThenTerm, *ElseTerm;
|
||||
SplitBlockAndInsertIfThenElse(Cmp, Ret, &ThenTerm, &ElseTerm);
|
||||
SplitBlockAndInsertIfThenElse(Cmp, Adjusted, &ThenTerm, &ElseTerm);
|
||||
|
||||
IRBuilder<> IRBPoison(ThenTerm);
|
||||
if (StackMallocIdx <= 4) {
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
; To test that asan does not break the musttail call contract.
|
||||
;
|
||||
; RUN: opt < %s -asan -asan-module -S -enable-new-pm=0 | FileCheck %s
|
||||
; RUN: opt < %s -passes='asan-pipeline' -S | FileCheck %s
|
||||
|
||||
define internal i32 @foo(i32* %p) sanitize_address {
|
||||
%rv = load i32, i32* %p
|
||||
ret i32 %rv
|
||||
}
|
||||
|
||||
declare void @alloca_test_use([10 x i8]*)
|
||||
define i32 @call_foo(i32* %a) sanitize_address {
|
||||
%x = alloca [10 x i8], align 1
|
||||
call void @alloca_test_use([10 x i8]* %x)
|
||||
%r = musttail call i32 @foo(i32* %a)
|
||||
ret i32 %r
|
||||
}
|
||||
|
||||
; CHECK-LABEL: define i32 @call_foo(i32* %a)
|
||||
; CHECK: %r = musttail call i32 @foo(i32* %a)
|
||||
; CHECK-NEXT: ret i32 %r
|
||||
|
||||
|
||||
define i32 @call_foo_cast(i32* %a) sanitize_address {
|
||||
%x = alloca [10 x i8], align 1
|
||||
call void @alloca_test_use([10 x i8]* %x)
|
||||
%r = musttail call i32 @foo(i32* %a)
|
||||
%t = bitcast i32 %r to i32
|
||||
ret i32 %t
|
||||
}
|
||||
|
||||
; CHECK-LABEL: define i32 @call_foo_cast(i32* %a)
|
||||
; CHECK: %r = musttail call i32 @foo(i32* %a)
|
||||
; CHECK-NEXT: %t = bitcast i32 %r to i32
|
||||
; CHECK-NEXT: ret i32 %t
|
Loading…
Reference in New Issue