Skip to content

Commit f25fd4b

Browse files
committed
StackProtector: insert check before musttail call.
`musttail` calls have to directly precede the return instruction (of their value), so any stack checks must be inserted before the call instead of in between it and the return.
1 parent e9d29d0 commit f25fd4b

File tree

3 files changed

+142
-4
lines changed

3 files changed

+142
-4
lines changed

llvm/lib/CodeGen/StackProtector.cpp

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -470,21 +470,36 @@ bool StackProtector::InsertStackProtectors() {
470470
// instrumentation has already been generated.
471471
HasIRCheck = true;
472472

473+
// If we're instrumenting a block with a musttail call, the check has to be
474+
// inserted before the call rather than between it and the return. The
475+
// verifier guarantees that a musttail call is either directly before the
476+
// return or with a single correct bitcast of the return value in between so
477+
// we don't need to worry about many situations here.
478+
Instruction *CheckLoc = RI;
479+
Instruction *Prev = RI->getPrevNonDebugInstruction();
480+
if (Prev && isa<CallInst>(Prev) && cast<CallInst>(Prev)->isMustTailCall())
481+
CheckLoc = Prev;
482+
else if (Prev) {
483+
Prev = Prev->getPrevNonDebugInstruction();
484+
if (Prev && isa<CallInst>(Prev) && cast<CallInst>(Prev)->isMustTailCall())
485+
CheckLoc = Prev;
486+
}
487+
473488
// Generate epilogue instrumentation. The epilogue intrumentation can be
474489
// function-based or inlined depending on which mechanism the target is
475490
// providing.
476491
if (Function *GuardCheck = TLI->getSSPStackGuardCheck(*M)) {
477492
// Generate the function-based epilogue instrumentation.
478493
// The target provides a guard check function, generate a call to it.
479-
IRBuilder<> B(RI);
494+
IRBuilder<> B(CheckLoc);
480495
LoadInst *Guard = B.CreateLoad(B.getInt8PtrTy(), AI, true, "Guard");
481496
CallInst *Call = B.CreateCall(GuardCheck, {Guard});
482497
Call->setAttributes(GuardCheck->getAttributes());
483498
Call->setCallingConv(GuardCheck->getCallingConv());
484499
} else {
485500
// Generate the epilogue with inline instrumentation.
486-
// If we do not support SelectionDAG based tail calls, generate IR level
487-
// tail calls.
501+
// If we do not support SelectionDAG based calls, generate IR level
502+
// calls.
488503
//
489504
// For each block with a return instruction, convert this:
490505
//
@@ -514,7 +529,8 @@ bool StackProtector::InsertStackProtectors() {
514529
BasicBlock *FailBB = CreateFailBB();
515530

516531
// Split the basic block before the return instruction.
517-
BasicBlock *NewBB = BB->splitBasicBlock(RI->getIterator(), "SP_return");
532+
BasicBlock *NewBB =
533+
BB->splitBasicBlock(CheckLoc->getIterator(), "SP_return");
518534

519535
// Update the dominator tree if we need to.
520536
if (DT && DT->isReachableFromEntry(BB)) {
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
; RUN: llc -mtriple=arm64-apple-macosx -fast-isel %s -o - -start-before=stack-protector -stop-after=stack-protector | FileCheck %s
2+
3+
@var = global [2 x i64]* null
4+
5+
declare void @callee()
6+
7+
define void @caller1() ssp {
8+
; CHECK-LABEL: define void @caller1()
9+
; Prologue:
10+
; CHECK: @llvm.stackguard
11+
12+
; CHECK: [[GUARD:%.*]] = call i8* @llvm.stackguard()
13+
; CHECK: [[TOKEN:%.*]] = load volatile i8*, i8** {{%.*}}
14+
; CHECK: [[TST:%.*]] = icmp eq i8* [[GUARD]], [[TOKEN]]
15+
; CHECK: br i1 [[TST]]
16+
17+
; CHECK: musttail call void @callee()
18+
; CHECK-NEXT: ret void
19+
%var = alloca [2 x i64]
20+
store [2 x i64]* %var, [2 x i64]** @var
21+
musttail call void @callee()
22+
ret void
23+
}
24+
25+
define void @justret() ssp {
26+
; CHECK-LABEL: define void @justret()
27+
; Prologue:
28+
; CHECK: @llvm.stackguard
29+
30+
; CHECK: [[GUARD:%.*]] = call i8* @llvm.stackguard()
31+
; CHECK: [[TOKEN:%.*]] = load volatile i8*, i8** {{%.*}}
32+
; CHECK: [[TST:%.*]] = icmp eq i8* [[GUARD]], [[TOKEN]]
33+
; CHECK: br i1 [[TST]]
34+
35+
; CHECK: ret void
36+
%var = alloca [2 x i64]
37+
store [2 x i64]* %var, [2 x i64]** @var
38+
br label %retblock
39+
40+
retblock:
41+
ret void
42+
}
43+
44+
45+
declare i64* @callee2()
46+
47+
define i8* @caller2() ssp {
48+
; CHECK-LABEL: define i8* @caller2()
49+
; Prologue:
50+
; CHECK: @llvm.stackguard
51+
52+
; CHECK: [[GUARD:%.*]] = call i8* @llvm.stackguard()
53+
; CHECK: [[TOKEN:%.*]] = load volatile i8*, i8** {{%.*}}
54+
; CHECK: [[TST:%.*]] = icmp eq i8* [[GUARD]], [[TOKEN]]
55+
; CHECK: br i1 [[TST]]
56+
57+
; CHECK: [[TMP:%.*]] = musttail call i64* @callee2()
58+
; CHECK-NEXT: [[RES:%.*]] = bitcast i64* [[TMP]] to i8*
59+
; CHECK-NEXT: ret i8* [[RES]]
60+
61+
%var = alloca [2 x i64]
62+
store [2 x i64]* %var, [2 x i64]** @var
63+
%tmp = musttail call i64* @callee2()
64+
%res = bitcast i64* %tmp to i8*
65+
ret i8* %res
66+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
; RUN: llc -mtriple=thumbv7-windows-msvc -fast-isel %s -o - -start-before=stack-protector -stop-after=stack-protector | FileCheck %s
2+
3+
@var = global [2 x i64]* null
4+
5+
declare void @callee()
6+
7+
define void @caller1() sspreq {
8+
; CHECK-LABEL: define void @caller1()
9+
; Prologue:
10+
11+
; CHECK: call void @__security_check_cookie
12+
13+
; CHECK: musttail call void @callee()
14+
; CHECK-NEXT: ret void
15+
%var = alloca [2 x i64]
16+
store [2 x i64]* %var, [2 x i64]** @var
17+
musttail call void @callee()
18+
ret void
19+
}
20+
21+
define void @justret() sspreq {
22+
; CHECK-LABEL: define void @justret()
23+
; Prologue:
24+
; CHECK: @llvm.stackguard
25+
26+
; CHECK: call void @__security_check_cookie
27+
28+
; CHECK: ret void
29+
%var = alloca [2 x i64]
30+
store [2 x i64]* %var, [2 x i64]** @var
31+
br label %retblock
32+
33+
retblock:
34+
ret void
35+
}
36+
37+
38+
declare i64* @callee2()
39+
40+
define i8* @caller2() sspreq {
41+
; CHECK-LABEL: define i8* @caller2()
42+
; Prologue:
43+
; CHECK: @llvm.stackguard
44+
45+
; CHECK: call void @__security_check_cookie
46+
47+
; CHECK: [[TMP:%.*]] = musttail call i64* @callee2()
48+
; CHECK-NEXT: [[RES:%.*]] = bitcast i64* [[TMP]] to i8*
49+
; CHECK-NEXT: ret i8* [[RES]]
50+
51+
%var = alloca [2 x i64]
52+
store [2 x i64]* %var, [2 x i64]** @var
53+
%tmp = musttail call i64* @callee2()
54+
%res = bitcast i64* %tmp to i8*
55+
ret i8* %res
56+
}

0 commit comments

Comments
 (0)