Skip to content

Commit de6d895

Browse files
committed
[Clang][CodeGen][UBSan] Add more precise attributes to recoverable ubsan handlers (llvm#130990)
This patch adds `memory(argmem: read, inaccessiblemem: readwrite) mustprogress` to **recoverable** ubsan handlers in order to unblock some memory/loop optimizations. It provides an average of 3% performance improvement on llvm-test-suite (except for 49 test failures due to ubsan diagnostics). Closes llvm#130093.
1 parent 7e53171 commit de6d895

File tree

4 files changed

+242
-130
lines changed

4 files changed

+242
-130
lines changed

clang/lib/CodeGen/CGExpr.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3645,6 +3645,18 @@ static void emitCheckHandlerCall(CodeGenFunction &CGF,
36453645
.addAttribute(llvm::Attribute::NoUnwind);
36463646
}
36473647
B.addUWTableAttr(llvm::UWTableKind::Default);
3648+
// Add more precise attributes to recoverable ubsan handlers for better
3649+
// optimizations.
3650+
if (CGF.CGM.getCodeGenOpts().OptimizationLevel > 0 && MayReturn) {
3651+
// __ubsan_handle_dynamic_type_cache_miss reads the vtable, which is also
3652+
// accessible by the current module.
3653+
if (CheckHandler != SanitizerHandler::DynamicTypeCacheMiss)
3654+
B.addMemoryAttr(llvm::MemoryEffects::argMemOnly(llvm::ModRefInfo::Ref) |
3655+
llvm::MemoryEffects::inaccessibleMemOnly());
3656+
// If the handler does not return, it must interact with the environment in
3657+
// an observable way.
3658+
B.addAttribute(llvm::Attribute::MustProgress);
3659+
}
36483660

36493661
llvm::FunctionCallee Fn = CGF.CGM.CreateRuntimeFunction(
36503662
FnType, FnName,

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

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
// CHECK: [[HANDLER_DIVREM_OVERFLOW]]:
3030
// CHECK-NEXT: [[TMP10:%.*]] = zext i32 [[X]] to i64, !nosanitize [[META2]]
3131
// CHECK-NEXT: [[TMP11:%.*]] = zext i32 [[Y]] to i64, !nosanitize [[META2]]
32-
// CHECK-NEXT: tail call void @__ubsan_handle_divrem_overflow_abort(ptr nonnull @[[GLOB1:[0-9]+]], i64 [[TMP10]], i64 [[TMP11]]) #[[ATTR6:[0-9]+]], !nosanitize [[META2]]
32+
// CHECK-NEXT: tail call void @__ubsan_handle_divrem_overflow_abort(ptr nonnull @[[GLOB1:[0-9]+]], i64 [[TMP10]], i64 [[TMP11]]) #[[ATTR8:[0-9]+]], !nosanitize [[META2]]
3333
// CHECK-NEXT: unreachable, !nosanitize [[META2]]
3434
// CHECK: [[CONT]]:
3535
// CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[X]], [[Y]]
@@ -75,7 +75,7 @@
7575
// REC: [[HANDLER_DIVREM_OVERFLOW]]:
7676
// REC-NEXT: [[TMP10:%.*]] = zext i32 [[X]] to i64, !nosanitize [[META2]]
7777
// REC-NEXT: [[TMP11:%.*]] = zext i32 [[Y]] to i64, !nosanitize [[META2]]
78-
// REC-NEXT: tail call void @__ubsan_handle_divrem_overflow(ptr nonnull @[[GLOB1:[0-9]+]], i64 [[TMP10]], i64 [[TMP11]]) #[[ATTR6:[0-9]+]], !nosanitize [[META2]]
78+
// REC-NEXT: tail call void @__ubsan_handle_divrem_overflow(ptr nonnull @[[GLOB1:[0-9]+]], i64 [[TMP10]], i64 [[TMP11]]) #[[ATTR8:[0-9]+]], !nosanitize [[META2]]
7979
// REC-NEXT: br label %[[CONT]], !nosanitize [[META2]]
8080
// REC: [[CONT]]:
8181
// REC-NEXT: [[DIV:%.*]] = sdiv i32 [[X]], [[Y]]
@@ -86,7 +86,7 @@ int div(int x, int y) {
8686
}
8787

8888
// CHECK-LABEL: define dso_local i32 @null(
89-
// CHECK-SAME: ptr noundef readonly captures(address_is_null) [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
89+
// CHECK-SAME: ptr noundef readonly captures(address_is_null) [[X:%.*]]) local_unnamed_addr #[[ATTR3:[0-9]+]] {
9090
// CHECK-NEXT: [[ENTRY:.*:]]
9191
// CHECK-NEXT: [[TMP0:%.*]] = icmp eq ptr [[X]], null, !nosanitize [[META2]]
9292
//
@@ -95,7 +95,7 @@ int div(int x, int y) {
9595
// CHECK-NEXT: [[DOTNOT1:%.*]] = and i1 [[TMP0]], [[TMP1]]
9696
// CHECK-NEXT: br i1 [[DOTNOT1]], label %[[HANDLER_TYPE_MISMATCH:.*]], label %[[CONT:.*]], !prof [[PROF4:![0-9]+]], !nosanitize [[META2]]
9797
// CHECK: [[HANDLER_TYPE_MISMATCH]]:
98-
// CHECK-NEXT: tail call void @__ubsan_handle_type_mismatch_v1_abort(ptr nonnull @[[GLOB2:[0-9]+]], i64 0) #[[ATTR6]], !nosanitize [[META2]]
98+
// CHECK-NEXT: tail call void @__ubsan_handle_type_mismatch_v1_abort(ptr nonnull @[[GLOB2:[0-9]+]], i64 0) #[[ATTR8]], !nosanitize [[META2]]
9999
// CHECK-NEXT: unreachable, !nosanitize [[META2]]
100100
// CHECK: [[CONT]]:
101101
// CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[X]], align 4, !tbaa [[TBAA5:![0-9]+]]
@@ -116,14 +116,14 @@ int div(int x, int y) {
116116
// TR-NEXT: ret i32 [[TMP2]]
117117
//
118118
// REC-LABEL: define dso_local i32 @null(
119-
// REC-SAME: ptr noundef readonly captures(address_is_null) [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
119+
// REC-SAME: ptr noundef readonly captures(address_is_null) [[X:%.*]]) local_unnamed_addr #[[ATTR3:[0-9]+]] {
120120
// REC-NEXT: [[ENTRY:.*:]]
121121
// REC-NEXT: [[TMP0:%.*]] = icmp eq ptr [[X]], null, !nosanitize [[META2]]
122122
// REC-NEXT: [[TMP1:%.*]] = tail call i1 @llvm.allow.ubsan.check(i8 29), !nosanitize [[META2]]
123123
// REC-NEXT: [[DOTNOT1:%.*]] = and i1 [[TMP0]], [[TMP1]]
124124
// REC-NEXT: br i1 [[DOTNOT1]], label %[[HANDLER_TYPE_MISMATCH:.*]], label %[[CONT:.*]], !prof [[PROF4:![0-9]+]], !nosanitize [[META2]]
125125
// REC: [[HANDLER_TYPE_MISMATCH]]:
126-
// REC-NEXT: tail call void @__ubsan_handle_type_mismatch_v1(ptr nonnull @[[GLOB2:[0-9]+]], i64 0) #[[ATTR6]], !nosanitize [[META2]]
126+
// REC-NEXT: tail call void @__ubsan_handle_type_mismatch_v1(ptr nonnull @[[GLOB2:[0-9]+]], i64 0) #[[ATTR8]], !nosanitize [[META2]]
127127
// REC-NEXT: br label %[[CONT]], !nosanitize [[META2]]
128128
// REC: [[CONT]]:
129129
// REC-NEXT: [[TMP2:%.*]] = load i32, ptr [[X]], align 4, !tbaa [[TBAA5:![0-9]+]]
@@ -146,7 +146,7 @@ int null(int* x) {
146146
// CHECK: [[HANDLER_ADD_OVERFLOW]]:
147147
// CHECK-NEXT: [[TMP3:%.*]] = zext i32 [[X]] to i64, !nosanitize [[META2]]
148148
// CHECK-NEXT: [[TMP4:%.*]] = zext i32 [[Y]] to i64, !nosanitize [[META2]]
149-
// CHECK-NEXT: tail call void @__ubsan_handle_add_overflow_abort(ptr nonnull @[[GLOB3:[0-9]+]], i64 [[TMP3]], i64 [[TMP4]]) #[[ATTR6]], !nosanitize [[META2]]
149+
// CHECK-NEXT: tail call void @__ubsan_handle_add_overflow_abort(ptr nonnull @[[GLOB3:[0-9]+]], i64 [[TMP3]], i64 [[TMP4]]) #[[ATTR8]], !nosanitize [[META2]]
150150
// CHECK-NEXT: unreachable, !nosanitize [[META2]]
151151
// CHECK: [[CONT]]:
152152
// CHECK-NEXT: [[TMP5:%.*]] = extractvalue { i32, i1 } [[TMP0]], 0, !nosanitize [[META2]]
@@ -178,7 +178,7 @@ int null(int* x) {
178178
// REC: [[HANDLER_ADD_OVERFLOW]]:
179179
// REC-NEXT: [[TMP3:%.*]] = zext i32 [[X]] to i64, !nosanitize [[META2]]
180180
// REC-NEXT: [[TMP4:%.*]] = zext i32 [[Y]] to i64, !nosanitize [[META2]]
181-
// REC-NEXT: tail call void @__ubsan_handle_add_overflow(ptr nonnull @[[GLOB3:[0-9]+]], i64 [[TMP3]], i64 [[TMP4]]) #[[ATTR6]], !nosanitize [[META2]]
181+
// REC-NEXT: tail call void @__ubsan_handle_add_overflow(ptr nonnull @[[GLOB3:[0-9]+]], i64 [[TMP3]], i64 [[TMP4]]) #[[ATTR8]], !nosanitize [[META2]]
182182
// REC-NEXT: br label %[[CONT]], !nosanitize [[META2]]
183183
// REC: [[CONT]]:
184184
// REC-NEXT: [[TMP5:%.*]] = extractvalue { i32, i1 } [[TMP0]], 0, !nosanitize [[META2]]
@@ -191,11 +191,11 @@ int overflow(int x, int y) {
191191
void use(double*);
192192

193193
// CHECK-LABEL: define dso_local double @lbounds(
194-
// CHECK-SAME: i32 noundef [[B:%.*]], i32 noundef [[I:%.*]]) local_unnamed_addr #[[ATTR0]] {
194+
// CHECK-SAME: i32 noundef [[B:%.*]], i32 noundef [[I:%.*]]) local_unnamed_addr #[[ATTR5:[0-9]+]] {
195195
// CHECK-NEXT: [[ENTRY:.*:]]
196196
// CHECK-NEXT: [[TMP0:%.*]] = zext i32 [[B]] to i64
197197
// CHECK-NEXT: [[VLA:%.*]] = alloca double, i64 [[TMP0]], align 16
198-
// CHECK-NEXT: call void @use(ptr noundef nonnull [[VLA]]) #[[ATTR7:[0-9]+]]
198+
// CHECK-NEXT: call void @use(ptr noundef nonnull [[VLA]]) #[[ATTR9:[0-9]+]]
199199
// CHECK-NEXT: [[IDXPROM:%.*]] = sext i32 [[I]] to i64
200200
// CHECK-NEXT: [[TMP1:%.*]] = icmp ule i64 [[TMP0]], [[IDXPROM]]
201201
//
@@ -208,7 +208,7 @@ void use(double*);
208208
// CHECK-NEXT: [[TMP5:%.*]] = load double, ptr [[ARRAYIDX]], align 8, !tbaa [[TBAA9:![0-9]+]]
209209
// CHECK-NEXT: ret double [[TMP5]]
210210
// CHECK: [[TRAP]]:
211-
// CHECK-NEXT: call void @__ubsan_handle_local_out_of_bounds_abort() #[[ATTR6]], !nosanitize [[META2]]
211+
// CHECK-NEXT: call void @__ubsan_handle_local_out_of_bounds_abort() #[[ATTR8]], !nosanitize [[META2]]
212212
// CHECK-NEXT: unreachable, !nosanitize [[META2]]
213213
//
214214
// TR-LABEL: define dso_local double @lbounds(
@@ -231,11 +231,11 @@ void use(double*);
231231
// TR-NEXT: unreachable, !nosanitize [[META2]]
232232
//
233233
// REC-LABEL: define dso_local double @lbounds(
234-
// REC-SAME: i32 noundef [[B:%.*]], i32 noundef [[I:%.*]]) local_unnamed_addr #[[ATTR0]] {
234+
// REC-SAME: i32 noundef [[B:%.*]], i32 noundef [[I:%.*]]) local_unnamed_addr #[[ATTR5:[0-9]+]] {
235235
// REC-NEXT: [[ENTRY:.*:]]
236236
// REC-NEXT: [[TMP0:%.*]] = zext i32 [[B]] to i64
237237
// REC-NEXT: [[VLA:%.*]] = alloca double, i64 [[TMP0]], align 16
238-
// REC-NEXT: call void @use(ptr noundef nonnull [[VLA]]) #[[ATTR5:[0-9]+]]
238+
// REC-NEXT: call void @use(ptr noundef nonnull [[VLA]]) #[[ATTR7:[0-9]+]]
239239
// REC-NEXT: [[IDXPROM:%.*]] = sext i32 [[I]] to i64
240240
// REC-NEXT: [[TMP1:%.*]] = icmp ule i64 [[TMP0]], [[IDXPROM]]
241241
// REC-NEXT: [[TMP2:%.*]] = call i1 @llvm.allow.ubsan.check(i8 71), !nosanitize [[META2]]
@@ -246,7 +246,7 @@ void use(double*);
246246
// REC-NEXT: [[TMP5:%.*]] = load double, ptr [[ARRAYIDX]], align 8, !tbaa [[TBAA9:![0-9]+]]
247247
// REC-NEXT: ret double [[TMP5]]
248248
// REC: [[TRAP]]:
249-
// REC-NEXT: call void @__ubsan_handle_local_out_of_bounds() #[[ATTR6]], !nosanitize [[META2]]
249+
// REC-NEXT: call void @__ubsan_handle_local_out_of_bounds() #[[ATTR8]], !nosanitize [[META2]]
250250
// REC-NEXT: br label %[[BB4]], !nosanitize [[META2]]
251251
//
252252
double lbounds(int b, int i) {

0 commit comments

Comments
 (0)