Skip to content

Commit f24a87d

Browse files
committed
[ubsan] Change ubsan-unique-traps to use nomerge instead of counter
llvm#65972 (continuation of https://reviews.llvm.org/D148654) had considered adding nomerge to ubsantrap, but did not proceed with that because of llvm#53011. Instead, it added a counter (based on TrapBB->getParent()->size()) to each ubsantrap call. However, this counter is not guaranteed to be unique after inlining, as shown by llvm#83470, which can result in ubsantraps being merged by the backend. llvm#101549 fixed has since fixed the nomerge limitation ("It sets nomerge flag for the node if the instruction has nomerge arrtibute."). This patch therefore takes advantage of nomerge instead of using the counter, guaranteeing that the ubsantraps are not merged. This patch is equivalent to llvm#83470 but also adds nomerge and updates the test that was precommitted in llvm#117649.
1 parent fe3c23b commit f24a87d

File tree

3 files changed

+110
-6
lines changed

3 files changed

+110
-6
lines changed

clang/lib/CodeGen/CGExpr.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3921,16 +3921,14 @@ void CodeGenFunction::EmitTrapCheck(llvm::Value *Checked,
39213921

39223922
llvm::CallInst *TrapCall = Builder.CreateCall(
39233923
CGM.getIntrinsic(llvm::Intrinsic::ubsantrap),
3924-
llvm::ConstantInt::get(CGM.Int8Ty,
3925-
ClSanitizeDebugDeoptimization
3926-
? TrapBB->getParent()->size()
3927-
: static_cast<uint64_t>(CheckHandlerID)));
3924+
llvm::ConstantInt::get(CGM.Int8Ty, CheckHandlerID));
39283925

39293926
if (!CGM.getCodeGenOpts().TrapFuncName.empty()) {
39303927
auto A = llvm::Attribute::get(getLLVMContext(), "trap-func-name",
39313928
CGM.getCodeGenOpts().TrapFuncName);
39323929
TrapCall->addFnAttr(A);
39333930
}
3931+
TrapCall->addFnAttr(llvm::Attribute::NoMerge);
39343932
TrapCall->setDoesNotReturn();
39353933
TrapCall->setDoesNotThrow();
39363934
Builder.CreateUnreachable();

clang/test/CodeGen/bounds-checking.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,11 +74,11 @@ char B2[10];
7474
// CHECK-LABEL: @f8
7575
void f8(int i, int k) {
7676
// NOOPTLOCAL: call void @llvm.ubsantrap(i8 3)
77-
// NOOPTARRAY: call void @llvm.ubsantrap(i8 2)
77+
// NOOPTARRAY: call void @llvm.ubsantrap(i8 18)
7878
B[i] = '\0';
7979

8080
// NOOPTLOCAL: call void @llvm.ubsantrap(i8 5)
81-
// NOOPTARRAY: call void @llvm.ubsantrap(i8 4)
81+
// NOOPTARRAY: call void @llvm.ubsantrap(i8 18)
8282
B2[k] = '\0';
8383
}
8484

clang/test/CodeGen/ubsan-trap-merge.c

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
// NOTE: Assertions have mostly been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5
2+
// The most important assertion is the attributes at the end of the file, which
3+
// shows that ubsan attaches 'nomerge' to each ubsantrap intrinsic.
4+
//
5+
// RUN: %clang -fsanitize=signed-integer-overflow -S -emit-llvm -fsanitize-trap=all -O3 -mllvm -ubsan-unique-traps %s -o - \
6+
// RUN: | FileCheck %s
7+
8+
#include <stdio.h>
9+
#include <stdlib.h>
10+
11+
// CHECK-LABEL: define dso_local range(i32 -2147483523, -2147483648) i32 @f(
12+
// CHECK-SAME: i32 noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
13+
// CHECK-NEXT: [[ENTRY:.*:]]
14+
// CHECK-NEXT: [[TMP0:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[X]], i32 125), !nosanitize [[META5:![0-9]+]]
15+
// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { i32, i1 } [[TMP0]], 1, !nosanitize [[META5]]
16+
// CHECK-NEXT: br i1 [[TMP1]], label %[[TRAP:.*]], label %[[CONT:.*]], !nosanitize [[META5]]
17+
// CHECK: [[TRAP]]:
18+
// CHECK-NEXT: tail call void @llvm.ubsantrap(i8 0) #[[ATTR4:[0-9]+]], !nosanitize [[META5]]
19+
// CHECK-NEXT: unreachable, !nosanitize [[META5]]
20+
// CHECK: [[CONT]]:
21+
// CHECK-NEXT: [[TMP2:%.*]] = extractvalue { i32, i1 } [[TMP0]], 0, !nosanitize [[META5]]
22+
// CHECK-NEXT: ret i32 [[TMP2]]
23+
//
24+
int f(int x) {
25+
return x + 125;
26+
}
27+
28+
// CHECK-LABEL: define dso_local range(i32 -2147483521, -2147483648) i32 @g(
29+
// CHECK-SAME: i32 noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
30+
// CHECK-NEXT: [[ENTRY:.*:]]
31+
// CHECK-NEXT: [[TMP0:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[X]], i32 127), !nosanitize [[META5]]
32+
// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { i32, i1 } [[TMP0]], 1, !nosanitize [[META5]]
33+
// CHECK-NEXT: br i1 [[TMP1]], label %[[TRAP:.*]], label %[[CONT:.*]], !nosanitize [[META5]]
34+
// CHECK: [[TRAP]]:
35+
// CHECK-NEXT: tail call void @llvm.ubsantrap(i8 0) #[[ATTR4]], !nosanitize [[META5]]
36+
// CHECK-NEXT: unreachable, !nosanitize [[META5]]
37+
// CHECK: [[CONT]]:
38+
// CHECK-NEXT: [[TMP2:%.*]] = extractvalue { i32, i1 } [[TMP0]], 0, !nosanitize [[META5]]
39+
// CHECK-NEXT: ret i32 [[TMP2]]
40+
//
41+
int g(int x) {
42+
return x + 127;
43+
}
44+
45+
// CHECK-LABEL: define dso_local range(i32 -2147483521, -2147483648) i32 @h(
46+
// CHECK-SAME: i32 noundef [[X:%.*]], i32 noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] {
47+
// CHECK-NEXT: [[ENTRY:.*:]]
48+
// CHECK-NEXT: [[TMP0:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[X]], i32 127), !nosanitize [[META5]]
49+
// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { i32, i1 } [[TMP0]], 1, !nosanitize [[META5]]
50+
// CHECK-NEXT: br i1 [[TMP1]], label %[[TRAP:.*]], label %[[CONT:.*]], !nosanitize [[META5]]
51+
// CHECK: [[TRAP]]:
52+
// CHECK-NEXT: tail call void @llvm.ubsantrap(i8 0) #[[ATTR4]], !nosanitize [[META5]]
53+
// CHECK-NEXT: unreachable, !nosanitize [[META5]]
54+
// CHECK: [[CONT]]:
55+
// CHECK-NEXT: [[TMP2:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[Y]], i32 129), !nosanitize [[META5]]
56+
// CHECK-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1, !nosanitize [[META5]]
57+
// CHECK-NEXT: br i1 [[TMP3]], label %[[TRAP1:.*]], label %[[CONT2:.*]], !nosanitize [[META5]]
58+
// CHECK: [[TRAP1]]:
59+
// CHECK-NEXT: tail call void @llvm.ubsantrap(i8 0) #[[ATTR4]], !nosanitize [[META5]]
60+
// CHECK-NEXT: unreachable, !nosanitize [[META5]]
61+
// CHECK: [[CONT2]]:
62+
// CHECK-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0, !nosanitize [[META5]]
63+
// CHECK-NEXT: [[TMP5:%.*]] = extractvalue { i32, i1 } [[TMP0]], 0, !nosanitize [[META5]]
64+
// CHECK-NEXT: [[COND:%.*]] = tail call i32 @llvm.smin.i32(i32 [[TMP5]], i32 [[TMP4]])
65+
// CHECK-NEXT: ret i32 [[COND]]
66+
//
67+
int h(int x, int y) {
68+
x += 127;
69+
y += 129;
70+
return x < y ? x : y;
71+
}
72+
73+
// CHECK-LABEL: define dso_local noundef i32 @m(
74+
// CHECK-SAME: i32 noundef [[X:%.*]], i32 noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] {
75+
// CHECK-NEXT: [[ENTRY:.*:]]
76+
// CHECK-NEXT: [[TMP0:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[X]], i32 125), !nosanitize [[META5]]
77+
// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { i32, i1 } [[TMP0]], 1, !nosanitize [[META5]]
78+
// CHECK-NEXT: br i1 [[TMP1]], label %[[TRAP_I:.*]], label %[[F_EXIT:.*]], !nosanitize [[META5]]
79+
// CHECK: [[TRAP_I]]:
80+
// CHECK-NEXT: tail call void @llvm.ubsantrap(i8 0) #[[ATTR4]], !nosanitize [[META5]]
81+
// CHECK-NEXT: unreachable, !nosanitize [[META5]]
82+
// CHECK: [[F_EXIT]]:
83+
// CHECK-NEXT: [[TMP2:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[Y]], i32 127), !nosanitize [[META5]]
84+
// CHECK-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1, !nosanitize [[META5]]
85+
// CHECK-NEXT: br i1 [[TMP3]], label %[[TRAP_I2:.*]], label %[[G_EXIT:.*]], !nosanitize [[META5]]
86+
// CHECK: [[TRAP_I2]]:
87+
// CHECK-NEXT: tail call void @llvm.ubsantrap(i8 0) #[[ATTR4]], !nosanitize [[META5]]
88+
// CHECK-NEXT: unreachable, !nosanitize [[META5]]
89+
// CHECK: [[G_EXIT]]:
90+
// CHECK-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP0]], 0, !nosanitize [[META5]]
91+
// CHECK-NEXT: [[TMP5:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0, !nosanitize [[META5]]
92+
// CHECK-NEXT: [[TMP6:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[TMP4]], i32 [[TMP5]]), !nosanitize [[META5]]
93+
// CHECK-NEXT: [[TMP7:%.*]] = extractvalue { i32, i1 } [[TMP6]], 1, !nosanitize [[META5]]
94+
// CHECK-NEXT: br i1 [[TMP7]], label %[[TRAP:.*]], label %[[CONT:.*]], !nosanitize [[META5]]
95+
// CHECK: [[TRAP]]:
96+
// CHECK-NEXT: tail call void @llvm.ubsantrap(i8 0) #[[ATTR4]], !nosanitize [[META5]]
97+
// CHECK-NEXT: unreachable, !nosanitize [[META5]]
98+
// CHECK: [[CONT]]:
99+
// CHECK-NEXT: [[TMP8:%.*]] = extractvalue { i32, i1 } [[TMP6]], 0, !nosanitize [[META5]]
100+
// CHECK-NEXT: ret i32 [[TMP8]]
101+
//
102+
int m(int x, int y) {
103+
return f(x) + g(y);
104+
}
105+
//.
106+
// CHECK: attributes #[[ATTR4]] = { nomerge noreturn nounwind }

0 commit comments

Comments
 (0)