Skip to content

Commit 1716e57

Browse files
committed
[𝘀𝗽𝗿] initial version
Created using spr 1.3.4
2 parents 8af4d20 + 77702b0 commit 1716e57

File tree

7 files changed

+106
-22
lines changed

7 files changed

+106
-22
lines changed

clang/lib/CodeGen/BackendUtil.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,9 @@ static cl::opt<PGOOptions::ColdFuncOpt> ClPGOColdFuncAttr(
118118

119119
extern cl::opt<InstrProfCorrelator::ProfCorrelatorKind> ProfileCorrelate;
120120
} // namespace llvm
121+
namespace clang {
122+
extern llvm::cl::opt<bool> ClSanitizeGuardChecks;
123+
}
121124

122125
namespace {
123126

@@ -1025,6 +1028,10 @@ void EmitAssemblyHelper::RunOptimizationPipeline(
10251028
PB.registerScalarOptimizerLateEPCallback([this](FunctionPassManager &FPM,
10261029
OptimizationLevel Level) {
10271030
BoundsCheckingPass::Options Options;
1031+
if (CodeGenOpts.SanitizeSkipHotCutoffs[SanitizerKind::SO_LocalBounds] ||
1032+
ClSanitizeGuardChecks) {
1033+
Options.GuardKind = SanitizerKind::SO_LocalBounds;
1034+
}
10281035
Options.Merge =
10291036
CodeGenOpts.SanitizeMergeHandlers.has(SanitizerKind::LocalBounds);
10301037
if (!CodeGenOpts.SanitizeTrap.has(SanitizerKind::LocalBounds)) {

clang/lib/CodeGen/CGExpr.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,13 @@
5252
using namespace clang;
5353
using namespace CodeGen;
5454

55+
namespace clang {
5556
// TODO: Introduce frontend options to enabled per sanitizers, similar to
5657
// `fsanitize-trap`.
57-
static llvm::cl::opt<bool> ClSanitizeGuardChecks(
58+
llvm::cl::opt<bool> ClSanitizeGuardChecks(
5859
"ubsan-guard-checks", llvm::cl::Optional,
5960
llvm::cl::desc("Guard UBSAN checks with `llvm.allow.ubsan.check()`."));
61+
} // namespace clang
6062

6163
//===--------------------------------------------------------------------===//
6264
// Defines for metadata

clang/test/CodeGen/allow-ubsan-check.c

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -174,12 +174,14 @@ void use(double*);
174174
// CHECK-NEXT: [[VLA:%.*]] = alloca double, i64 [[TMP0]], align 16
175175
// CHECK-NEXT: call void @use(ptr noundef nonnull [[VLA]]) #[[ATTR7:[0-9]+]]
176176
// CHECK-NEXT: [[IDXPROM:%.*]] = sext i32 [[I]] to i64
177-
// CHECK-NEXT: [[DOTNOT:%.*]] = icmp ugt i64 [[TMP0]], [[IDXPROM]]
178-
// CHECK-NEXT: br i1 [[DOTNOT]], label %[[BB1:.*]], label %[[TRAP:.*]]
179-
// CHECK: [[BB1]]:
177+
// CHECK-NEXT: [[TMP1:%.*]] = icmp ule i64 [[TMP0]], [[IDXPROM]]
178+
// CHECK-NEXT: [[TMP2:%.*]] = call i1 @llvm.allow.ubsan.check(i8 71), !nosanitize [[META2]]
179+
// CHECK-NEXT: [[TMP3:%.*]] = and i1 [[TMP1]], [[TMP2]], !nosanitize [[META2]]
180+
// CHECK-NEXT: br i1 [[TMP3]], label %[[TRAP:.*]], label %[[BB4:.*]]
181+
// CHECK: [[BB4]]:
180182
// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds double, ptr [[VLA]], i64 [[IDXPROM]]
181-
// CHECK-NEXT: [[TMP2:%.*]] = load double, ptr [[ARRAYIDX]], align 8, !tbaa [[TBAA8:![0-9]+]]
182-
// CHECK-NEXT: ret double [[TMP2]]
183+
// CHECK-NEXT: [[TMP5:%.*]] = load double, ptr [[ARRAYIDX]], align 8, !tbaa [[TBAA8:![0-9]+]]
184+
// CHECK-NEXT: ret double [[TMP5]]
183185
// CHECK: [[TRAP]]:
184186
// CHECK-NEXT: call void @__ubsan_handle_local_out_of_bounds_abort() #[[ATTR6]], !nosanitize [[META2]]
185187
// CHECK-NEXT: unreachable, !nosanitize [[META2]]
@@ -191,12 +193,14 @@ void use(double*);
191193
// TR-NEXT: [[VLA:%.*]] = alloca double, i64 [[TMP0]], align 16
192194
// TR-NEXT: call void @use(ptr noundef nonnull [[VLA]]) #[[ATTR6:[0-9]+]]
193195
// TR-NEXT: [[IDXPROM:%.*]] = sext i32 [[I]] to i64
194-
// TR-NEXT: [[DOTNOT:%.*]] = icmp ugt i64 [[TMP0]], [[IDXPROM]]
195-
// TR-NEXT: br i1 [[DOTNOT]], label %[[BB1:.*]], label %[[TRAP:.*]]
196-
// TR: [[BB1]]:
196+
// TR-NEXT: [[TMP1:%.*]] = icmp ule i64 [[TMP0]], [[IDXPROM]]
197+
// TR-NEXT: [[TMP2:%.*]] = call i1 @llvm.allow.ubsan.check(i8 71), !nosanitize [[META2]]
198+
// TR-NEXT: [[TMP3:%.*]] = and i1 [[TMP1]], [[TMP2]], !nosanitize [[META2]]
199+
// TR-NEXT: br i1 [[TMP3]], label %[[TRAP:.*]], label %[[BB4:.*]]
200+
// TR: [[BB4]]:
197201
// TR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds double, ptr [[VLA]], i64 [[IDXPROM]]
198-
// TR-NEXT: [[TMP2:%.*]] = load double, ptr [[ARRAYIDX]], align 8, !tbaa [[TBAA7:![0-9]+]]
199-
// TR-NEXT: ret double [[TMP2]]
202+
// TR-NEXT: [[TMP5:%.*]] = load double, ptr [[ARRAYIDX]], align 8, !tbaa [[TBAA7:![0-9]+]]
203+
// TR-NEXT: ret double [[TMP5]]
200204
// TR: [[TRAP]]:
201205
// TR-NEXT: call void @llvm.ubsantrap(i8 3) #[[ATTR5]], !nosanitize [[META2]]
202206
// TR-NEXT: unreachable, !nosanitize [[META2]]
@@ -208,15 +212,17 @@ void use(double*);
208212
// REC-NEXT: [[VLA:%.*]] = alloca double, i64 [[TMP0]], align 16
209213
// REC-NEXT: call void @use(ptr noundef nonnull [[VLA]]) #[[ATTR5:[0-9]+]]
210214
// REC-NEXT: [[IDXPROM:%.*]] = sext i32 [[I]] to i64
211-
// REC-NEXT: [[DOTNOT:%.*]] = icmp ugt i64 [[TMP0]], [[IDXPROM]]
212-
// REC-NEXT: br i1 [[DOTNOT]], label %[[BB1:.*]], label %[[TRAP:.*]]
213-
// REC: [[BB1]]:
215+
// REC-NEXT: [[TMP1:%.*]] = icmp ule i64 [[TMP0]], [[IDXPROM]]
216+
// REC-NEXT: [[TMP2:%.*]] = call i1 @llvm.allow.ubsan.check(i8 71), !nosanitize [[META2]]
217+
// REC-NEXT: [[TMP3:%.*]] = and i1 [[TMP1]], [[TMP2]], !nosanitize [[META2]]
218+
// REC-NEXT: br i1 [[TMP3]], label %[[TRAP:.*]], label %[[BB4:.*]]
219+
// REC: [[BB4]]:
214220
// REC-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds double, ptr [[VLA]], i64 [[IDXPROM]]
215-
// REC-NEXT: [[TMP2:%.*]] = load double, ptr [[ARRAYIDX]], align 8, !tbaa [[TBAA8:![0-9]+]]
216-
// REC-NEXT: ret double [[TMP2]]
221+
// REC-NEXT: [[TMP5:%.*]] = load double, ptr [[ARRAYIDX]], align 8, !tbaa [[TBAA8:![0-9]+]]
222+
// REC-NEXT: ret double [[TMP5]]
217223
// REC: [[TRAP]]:
218224
// REC-NEXT: call void @__ubsan_handle_local_out_of_bounds() #[[ATTR6]], !nosanitize [[META2]]
219-
// REC-NEXT: br label %[[BB1]], !nosanitize [[META2]]
225+
// REC-NEXT: br label %[[BB4]], !nosanitize [[META2]]
220226
//
221227
double lbounds(int b, int i) {
222228
double a[b];

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-GUARDRT
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-GUARDRT-LABEL: define void @f1(
148+
; RT-GUARDRT-SAME: i64 [[X:%.*]]) #[[ATTR0:[0-9]+]] {
149+
; RT-GUARDRT-NEXT: [[TMP1:%.*]] = mul i64 16, [[X]]
150+
; RT-GUARDRT-NEXT: [[TMP2:%.*]] = alloca i128, i64 [[X]], align 8
151+
; RT-GUARDRT-NEXT: [[TMP3:%.*]] = sub i64 [[TMP1]], 0, !nosanitize [[META0:![0-9]+]]
152+
; RT-GUARDRT-NEXT: [[TMP4:%.*]] = icmp ult i64 [[TMP3]], 16, !nosanitize [[META0]]
153+
; RT-GUARDRT-NEXT: [[TMP5:%.*]] = or i1 false, [[TMP4]], !nosanitize [[META0]]
154+
; RT-GUARDRT-NEXT: [[TMP6:%.*]] = or i1 false, [[TMP5]], !nosanitize [[META0]]
155+
; RT-GUARDRT-NEXT: [[TMP7:%.*]] = call i1 @llvm.allow.ubsan.check(i8 -5), !nosanitize [[META0]]
156+
; RT-GUARDRT-NEXT: [[TMP8:%.*]] = and i1 [[TMP6]], [[TMP7]], !nosanitize [[META0]]
157+
; RT-GUARDRT-NEXT: br i1 [[TMP8]], label %[[TRAP:.*]], label %[[BB9:.*]]
158+
; RT-GUARDRT: [[BB9]]:
159+
; RT-GUARDRT-NEXT: [[TMP10:%.*]] = load i128, ptr [[TMP2]], align 4
160+
; RT-GUARDRT-NEXT: ret void
161+
; RT-GUARDRT: [[TRAP]]:
162+
; RT-GUARDRT-NEXT: call void @__ubsan_handle_local_out_of_bounds() #[[ATTR2:[0-9]+]], !nosanitize [[META0]]
163+
; RT-GUARDRT-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-GUARDRT: attributes #[[ATTR0]] = { nounwind }
201+
; RT-GUARDRT: attributes #[[ATTR1:[0-9]+]] = { nocallback nofree nosync nounwind willreturn memory(inaccessiblemem: write) }
202+
; RT-GUARDRT: 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-GUARDRT: [[META0]] = !{}
221+
;.

0 commit comments

Comments
 (0)