Skip to content

Commit 1a7d46f

Browse files
authored
[BoundsChecking] Add guard= pass parameter (llvm#122575)
And use that as an argument for allow_ubsan_check when needed. Other ubsan checks use SanitizerKind, but those are known to the clang only. So make it a parameter in LLVM.
1 parent 092d628 commit 1a7d46f

File tree

4 files changed

+74
-5
lines changed

4 files changed

+74
-5
lines changed

llvm/include/llvm/Transforms/Instrumentation/BoundsChecking.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ class BoundsCheckingPass : public PassInfoMixin<BoundsCheckingPass> {
2929
};
3030
std::optional<Runtime> Rt; // Trap if empty.
3131
bool Merge = false;
32+
std::optional<int8_t> GuardKind; // `allow_ubsan_check` argument.
3233
};
3334

3435
BoundsCheckingPass(Options Opts) : Opts(Opts) {}

llvm/lib/Passes/PassBuilder.cpp

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1315,10 +1315,18 @@ parseBoundsCheckingOptions(StringRef Params) {
13151315
} else if (ParamName == "merge") {
13161316
Options.Merge = true;
13171317
} else {
1318-
return make_error<StringError>(
1319-
formatv("invalid BoundsChecking pass parameter '{0}' ", ParamName)
1320-
.str(),
1321-
inconvertibleErrorCode());
1318+
StringRef ParamEQ;
1319+
StringRef Val;
1320+
std::tie(ParamEQ, Val) = ParamName.split('=');
1321+
int8_t Id = 0;
1322+
if (ParamEQ == "guard" && !Val.getAsInteger(0, Id)) {
1323+
Options.GuardKind = Id;
1324+
} else {
1325+
return make_error<StringError>(
1326+
formatv("invalid BoundsChecking pass parameter '{0}' ", ParamName)
1327+
.str(),
1328+
inconvertibleErrorCode());
1329+
}
13221330
}
13231331
}
13241332
return Options;

llvm/lib/Transforms/Instrumentation/BoundsChecking.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,8 +214,15 @@ static bool addBoundsChecking(Function &F, TargetLibraryInfo &TLI,
214214
Or = getBoundsCheckCond(AI->getPointerOperand(), AI->getValOperand(),
215215
DL, TLI, ObjSizeEval, IRB, SE);
216216
}
217-
if (Or)
217+
if (Or) {
218+
if (Opts.GuardKind) {
219+
llvm::Value *Allow = IRB.CreateIntrinsic(
220+
IRB.getInt1Ty(), Intrinsic::allow_ubsan_check,
221+
{llvm::ConstantInt::getSigned(IRB.getInt8Ty(), *Opts.GuardKind)});
222+
Or = IRB.CreateAnd(Or, Allow);
223+
}
218224
TrapInfo.push_back(std::make_pair(&I, Or));
225+
}
219226
}
220227

221228
std::string Name;
@@ -299,5 +306,7 @@ void BoundsCheckingPass::printPipeline(
299306
}
300307
if (Opts.Merge)
301308
OS << ";merge";
309+
if (Opts.GuardKind)
310+
OS << ";guard=" << static_cast<int>(*Opts.GuardKind);
302311
OS << ">";
303312
}

llvm/test/Instrumentation/BoundsChecking/runtimes.ll

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
; RUN: opt < %s -passes='bounds-checking<min-rt>' -S | FileCheck %s --check-prefixes=MINRT-NOMERGE
1010
; RUN: opt < %s -passes='bounds-checking<min-rt-abort>' -S | FileCheck %s --check-prefixes=MINRTABORT-NOMERGE
1111
;
12+
; RUN: opt < %s -passes='bounds-checking<trap;guard=3>' -S | FileCheck %s --check-prefixes=TR-GUARD
13+
; RUN: opt < %s -passes='bounds-checking<rt;guard=-5>' -S | FileCheck %s --check-prefixes=RT-GUARD
1214
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
1315

1416
define void @f1(i64 %x) nounwind {
@@ -123,6 +125,42 @@ define void @f1(i64 %x) nounwind {
123125
; MINRTABORT-NOMERGE: [[TRAP]]:
124126
; MINRTABORT-NOMERGE-NEXT: call void @__ubsan_handle_local_out_of_bounds_minimal_abort() #[[ATTR2:[0-9]+]], !nosanitize [[META0]]
125127
; MINRTABORT-NOMERGE-NEXT: unreachable, !nosanitize [[META0]]
128+
;
129+
; TR-GUARD-LABEL: define void @f1(
130+
; TR-GUARD-SAME: i64 [[X:%.*]]) #[[ATTR0:[0-9]+]] {
131+
; TR-GUARD-NEXT: [[TMP1:%.*]] = mul i64 16, [[X]]
132+
; TR-GUARD-NEXT: [[TMP2:%.*]] = alloca i128, i64 [[X]], align 8
133+
; TR-GUARD-NEXT: [[TMP3:%.*]] = sub i64 [[TMP1]], 0, !nosanitize [[META0:![0-9]+]]
134+
; TR-GUARD-NEXT: [[TMP4:%.*]] = icmp ult i64 [[TMP3]], 16, !nosanitize [[META0]]
135+
; TR-GUARD-NEXT: [[TMP5:%.*]] = or i1 false, [[TMP4]], !nosanitize [[META0]]
136+
; TR-GUARD-NEXT: [[TMP6:%.*]] = or i1 false, [[TMP5]], !nosanitize [[META0]]
137+
; TR-GUARD-NEXT: [[TMP7:%.*]] = call i1 @llvm.allow.ubsan.check(i8 3), !nosanitize [[META0]]
138+
; TR-GUARD-NEXT: [[TMP8:%.*]] = and i1 [[TMP6]], [[TMP7]], !nosanitize [[META0]]
139+
; TR-GUARD-NEXT: br i1 [[TMP8]], label %[[TRAP:.*]], label %[[BB9:.*]]
140+
; TR-GUARD: [[BB9]]:
141+
; TR-GUARD-NEXT: [[TMP10:%.*]] = load i128, ptr [[TMP2]], align 4
142+
; TR-GUARD-NEXT: ret void
143+
; TR-GUARD: [[TRAP]]:
144+
; TR-GUARD-NEXT: call void @llvm.ubsantrap(i8 3) #[[ATTR3:[0-9]+]], !nosanitize [[META0]]
145+
; TR-GUARD-NEXT: unreachable, !nosanitize [[META0]]
146+
;
147+
; RT-GUARD-LABEL: define void @f1(
148+
; RT-GUARD-SAME: i64 [[X:%.*]]) #[[ATTR0:[0-9]+]] {
149+
; RT-GUARD-NEXT: [[TMP1:%.*]] = mul i64 16, [[X]]
150+
; RT-GUARD-NEXT: [[TMP2:%.*]] = alloca i128, i64 [[X]], align 8
151+
; RT-GUARD-NEXT: [[TMP3:%.*]] = sub i64 [[TMP1]], 0, !nosanitize [[META0:![0-9]+]]
152+
; RT-GUARD-NEXT: [[TMP4:%.*]] = icmp ult i64 [[TMP3]], 16, !nosanitize [[META0]]
153+
; RT-GUARD-NEXT: [[TMP5:%.*]] = or i1 false, [[TMP4]], !nosanitize [[META0]]
154+
; RT-GUARD-NEXT: [[TMP6:%.*]] = or i1 false, [[TMP5]], !nosanitize [[META0]]
155+
; RT-GUARD-NEXT: [[TMP7:%.*]] = call i1 @llvm.allow.ubsan.check(i8 -5), !nosanitize [[META0]]
156+
; RT-GUARD-NEXT: [[TMP8:%.*]] = and i1 [[TMP6]], [[TMP7]], !nosanitize [[META0]]
157+
; RT-GUARD-NEXT: br i1 [[TMP8]], label %[[TRAP:.*]], label %[[BB9:.*]]
158+
; RT-GUARD: [[BB9]]:
159+
; RT-GUARD-NEXT: [[TMP10:%.*]] = load i128, ptr [[TMP2]], align 4
160+
; RT-GUARD-NEXT: ret void
161+
; RT-GUARD: [[TRAP]]:
162+
; RT-GUARD-NEXT: call void @__ubsan_handle_local_out_of_bounds() #[[ATTR2:[0-9]+]], !nosanitize [[META0]]
163+
; RT-GUARD-NEXT: br label %[[BB9]], !nosanitize [[META0]]
126164
;
127165
%1 = alloca i128, i64 %x
128166
%3 = load i128, ptr %1, align 4
@@ -154,6 +192,15 @@ define void @f1(i64 %x) nounwind {
154192
; MINRTABORT-NOMERGE: attributes #[[ATTR1:[0-9]+]] = { noreturn nounwind }
155193
; MINRTABORT-NOMERGE: attributes #[[ATTR2]] = { nomerge noreturn nounwind }
156194
;.
195+
; TR-GUARD: attributes #[[ATTR0]] = { nounwind }
196+
; TR-GUARD: attributes #[[ATTR1:[0-9]+]] = { nocallback nofree nosync nounwind willreturn memory(inaccessiblemem: write) }
197+
; TR-GUARD: attributes #[[ATTR2:[0-9]+]] = { cold noreturn nounwind }
198+
; TR-GUARD: attributes #[[ATTR3]] = { nomerge noreturn nounwind }
199+
;.
200+
; RT-GUARD: attributes #[[ATTR0]] = { nounwind }
201+
; RT-GUARD: attributes #[[ATTR1:[0-9]+]] = { nocallback nofree nosync nounwind willreturn memory(inaccessiblemem: write) }
202+
; RT-GUARD: attributes #[[ATTR2]] = { nomerge nounwind }
203+
;.
157204
; TR: [[META0]] = !{}
158205
;.
159206
; RT: [[META0]] = !{}
@@ -168,3 +215,7 @@ define void @f1(i64 %x) nounwind {
168215
;.
169216
; MINRTABORT-NOMERGE: [[META0]] = !{}
170217
;.
218+
; TR-GUARD: [[META0]] = !{}
219+
;.
220+
; RT-GUARD: [[META0]] = !{}
221+
;.

0 commit comments

Comments
 (0)