Skip to content

Commit f7a6c34

Browse files
committed
[mte] support more complicated lifetimes (e.g. for exceptions).
Reviewed By: eugenis Differential Revision: https://reviews.llvm.org/D118848
1 parent 7756b34 commit f7a6c34

File tree

5 files changed

+59
-10
lines changed

5 files changed

+59
-10
lines changed

‎llvm/include/llvm/Transforms/Utils/MemoryTaggingSupport.h‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ bool forAllReachableExits(const DominatorTree &DT, const PostDominatorTree &PDT,
6767

6868
bool isStandardLifetime(const SmallVectorImpl<IntrinsicInst *> &LifetimeStart,
6969
const SmallVectorImpl<IntrinsicInst *> &LifetimeEnd,
70-
const DominatorTree &DT, size_t MaxLifetimes);
70+
const DominatorTree *DT, size_t MaxLifetimes);
7171
} // namespace llvm
7272

7373
#endif

‎llvm/lib/Target/AArch64/AArch64StackTagging.cpp‎

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,12 @@ static cl::opt<unsigned>
7878
ClMergeInitSizeLimit("stack-tagging-merge-init-size-limit", cl::init(272),
7979
cl::Hidden);
8080

81+
static cl::opt<size_t> ClMaxLifetimes(
82+
"stack-tagging-max-lifetimes-for-alloca", cl::Hidden, cl::init(3),
83+
cl::ReallyHidden,
84+
cl::desc("How many lifetime ends to handle for a single alloca."),
85+
cl::Optional);
86+
8187
static const Align kTagGranuleSize = Align(16);
8288

8389
namespace {
@@ -645,14 +651,17 @@ bool AArch64StackTagging::runOnFunction(Function &Fn) {
645651
Info.AI->replaceAllUsesWith(TagPCall);
646652
TagPCall->setOperand(0, Info.AI);
647653

654+
bool StandardLifetime =
655+
UnrecognizedLifetimes.empty() &&
656+
isStandardLifetime(Info.LifetimeStart, Info.LifetimeEnd, DT,
657+
ClMaxLifetimes);
648658
// Calls to functions that may return twice (e.g. setjmp) confuse the
649659
// postdominator analysis, and will leave us to keep memory tagged after
650660
// function return. Work around this by always untagging at every return
651661
// statement if return_twice functions are called.
652-
if (UnrecognizedLifetimes.empty() && Info.LifetimeStart.size() == 1 &&
653-
Info.LifetimeEnd.size() == 1 && !CallsReturnTwice) {
662+
if (UnrecognizedLifetimes.empty() && StandardLifetime &&
663+
!CallsReturnTwice) {
654664
IntrinsicInst *Start = Info.LifetimeStart[0];
655-
IntrinsicInst *End = Info.LifetimeEnd[0];
656665
uint64_t Size =
657666
cast<ConstantInt>(Start->getArgOperand(0))->getZExtValue();
658667
Size = alignTo(Size, kTagGranuleSize);
@@ -661,8 +670,10 @@ bool AArch64StackTagging::runOnFunction(Function &Fn) {
661670
auto TagEnd = [&](Instruction *Node) { untagAlloca(AI, Node, Size); };
662671
if (!DT || !PDT ||
663672
!forAllReachableExits(*DT, *PDT, Start, Info.LifetimeEnd, RetVec,
664-
TagEnd))
665-
End->eraseFromParent();
673+
TagEnd)) {
674+
for (auto *End : Info.LifetimeEnd)
675+
End->eraseFromParent();
676+
}
666677
} else {
667678
uint64_t Size = Info.AI->getAllocationSizeInBits(*DL).getValue() / 8;
668679
Value *Ptr = IRB.CreatePointerCast(TagPCall, IRB.getInt8PtrTy());

‎llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1382,7 +1382,7 @@ bool HWAddressSanitizer::instrumentStack(
13821382
};
13831383
bool StandardLifetime =
13841384
UnrecognizedLifetimes.empty() &&
1385-
isStandardLifetime(Info.LifetimeStart, Info.LifetimeEnd, GetDT(),
1385+
isStandardLifetime(Info.LifetimeStart, Info.LifetimeEnd, &GetDT(),
13861386
ClMaxLifetimes);
13871387
if (ShouldDetectUseAfterScope && StandardLifetime) {
13881388
IntrinsicInst *Start = Info.LifetimeStart[0];

‎llvm/lib/Transforms/Utils/MemoryTaggingSupport.cpp‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,15 @@
1515
namespace llvm {
1616
namespace {
1717
bool maybeReachableFromEachOther(const SmallVectorImpl<IntrinsicInst *> &Insts,
18-
const DominatorTree &DT, size_t MaxLifetimes) {
18+
const DominatorTree *DT, size_t MaxLifetimes) {
1919
// If we have too many lifetime ends, give up, as the algorithm below is N^2.
2020
if (Insts.size() > MaxLifetimes)
2121
return true;
2222
for (size_t I = 0; I < Insts.size(); ++I) {
2323
for (size_t J = 0; J < Insts.size(); ++J) {
2424
if (I == J)
2525
continue;
26-
if (isPotentiallyReachable(Insts[I], Insts[J], nullptr, &DT))
26+
if (isPotentiallyReachable(Insts[I], Insts[J], nullptr, DT))
2727
return true;
2828
}
2929
}
@@ -33,7 +33,7 @@ bool maybeReachableFromEachOther(const SmallVectorImpl<IntrinsicInst *> &Insts,
3333

3434
bool isStandardLifetime(const SmallVectorImpl<IntrinsicInst *> &LifetimeStart,
3535
const SmallVectorImpl<IntrinsicInst *> &LifetimeEnd,
36-
const DominatorTree &DT, size_t MaxLifetimes) {
36+
const DominatorTree *DT, size_t MaxLifetimes) {
3737
// An alloca that has exactly one start and end in every possible execution.
3838
// If it has multiple ends, they have to be unreachable from each other, so
3939
// at most one of them is actually used for each execution of the function.
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
; RUN: opt -S -aarch64-stack-tagging -stack-tagging-use-stack-safety=0 %s -o - | FileCheck %s
2+
3+
target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
4+
target triple = "aarch64-arm-unknown-eabi"
5+
6+
define void @f(i1 %cond) local_unnamed_addr sanitize_memtag {
7+
start:
8+
; CHECK-LABEL: start:
9+
%a = alloca i8, i32 48, align 8
10+
call void @llvm.lifetime.start.p0i8(i64 48, i8* nonnull %a)
11+
; CHECK: call void @llvm.aarch64.settag(i8* %a.tag, i64 48)
12+
br i1 %cond, label %next0, label %next1
13+
14+
next0:
15+
; CHECK-LABEL: next0:
16+
; CHECK: call void @llvm.aarch64.settag
17+
call void @llvm.lifetime.end.p0i8(i64 40, i8* nonnull %a)
18+
br label %exit0
19+
20+
exit0:
21+
; CHECK-LABEL: exit0:
22+
; CHECK-NOT: call void @llvm.aarch64.settag
23+
ret void
24+
25+
next1:
26+
; CHECK-LABEL: next1:
27+
; CHECK: call void @llvm.aarch64.settag
28+
call void @llvm.lifetime.end.p0i8(i64 40, i8* nonnull %a)
29+
br label %exit1
30+
31+
exit1:
32+
; CHECK-LABEL: exit1:
33+
; CHECK-NOT: call void @llvm.aarch64.settag
34+
ret void
35+
}
36+
37+
declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture)
38+
declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture)

0 commit comments

Comments
 (0)