Skip to content

Commit a9088dd

Browse files
TNorthovervarungandhi-apple
authored andcommitted
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. (cherry picked from commit f25fd4b)
1 parent 3f79a31 commit a9088dd

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)