1 | // RUN: %clang_cc1 -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s --check-prefix=CHECK |
2 | // RUN: %clang_cc1 -fsanitize=implicit-signed-integer-truncation,implicit-integer-sign-change -fno-sanitize-recover=implicit-signed-integer-truncation,implicit-integer-sign-change -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s -implicit-check-not="call void @__ubsan_handle_implicit_conversion" --check-prefixes=CHECK,CHECK-SANITIZE,CHECK-SANITIZE-ANYRECOVER,CHECK-SANITIZE-NORECOVER,CHECK-SANITIZE-UNREACHABLE |
3 | // RUN: %clang_cc1 -fsanitize=implicit-signed-integer-truncation,implicit-integer-sign-change -fsanitize-recover=implicit-signed-integer-truncation,implicit-integer-sign-change -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s -implicit-check-not="call void @__ubsan_handle_implicit_conversion" --check-prefixes=CHECK,CHECK-SANITIZE,CHECK-SANITIZE-ANYRECOVER,CHECK-SANITIZE-RECOVER |
4 | // RUN: %clang_cc1 -fsanitize=implicit-signed-integer-truncation,implicit-integer-sign-change -fsanitize-trap=implicit-signed-integer-truncation,implicit-integer-sign-change -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s -implicit-check-not="call void @__ubsan_handle_implicit_conversion" --check-prefixes=CHECK,CHECK-SANITIZE,CHECK-SANITIZE-TRAP,CHECK-SANITIZE-UNREACHABLE |
5 | |
6 | // CHECK-SANITIZE-ANYRECOVER: @[[UNSIGNED_INT:.*]] = {{.*}} c"'unsigned int'\00" } |
7 | // CHECK-SANITIZE-ANYRECOVER-NEXT: @[[SIGNED_CHAR:.*]] = {{.*}} c"'signed char'\00" } |
8 | // CHECK-SANITIZE-ANYRECOVER-NEXT: @[[LINE_100_SIGNED_TRUNCATION_OR_SIGN_CHANGE:.*]] = {{.*}}, i32 100, i32 10 }, {{.*}}* @[[UNSIGNED_INT]], {{.*}}* @[[SIGNED_CHAR]], i8 4 } |
9 | // CHECK-SANITIZE-ANYRECOVER-NEXT: @[[LINE_200_SIGN_CHANGE:.*]] = {{.*}}, i32 200, i32 10 }, {{.*}}* @[[UNSIGNED_INT]], {{.*}}* @[[SIGNED_CHAR]], i8 3 } |
10 | // CHECK-SANITIZE-ANYRECOVER-NEXT: @[[LINE_300_SIGN_CHANGE:.*]] = {{.*}}, i32 300, i32 10 }, {{.*}}* @[[UNSIGNED_INT]], {{.*}}* @[[SIGNED_CHAR]], i8 3 } |
11 | // CHECK-SANITIZE-ANYRECOVER-NEXT: @[[LINE_400_SIGNED_TRUNCATION:.*]] = {{.*}}, i32 400, i32 10 }, {{.*}}* @[[UNSIGNED_INT]], {{.*}}* @[[SIGNED_CHAR]], i8 2 } |
12 | |
13 | //============================================================================// |
14 | // Both sanitizers are enabled, and not disabled per-function. |
15 | //============================================================================// |
16 | |
17 | // CHECK-LABEL: @unsigned_int_to_signed_char |
18 | // CHECK-SAME: (i32 %[[SRC:.*]]) |
19 | signed char unsigned_int_to_signed_char(unsigned int src) { |
20 | // CHECK-NEXT: [[ENTRY:.*]]: |
21 | // CHECK-NEXT: %[[SRC_ADDR:.*]] = alloca i32 |
22 | // CHECK-NEXT: store i32 %[[SRC]], i32* %[[SRC_ADDR]] |
23 | // CHECK-NEXT: %[[DST:.*]] = load i32, i32* %[[SRC_ADDR]] |
24 | // CHECK-NEXT: %[[CONV:.*]] = trunc i32 %[[DST]] to i8 |
25 | // CHECK-SANITIZE-NEXT: %[[DST_NEGATIVITYCHECK:.*]] = icmp slt i8 %[[CONV]], 0, !nosanitize |
26 | // CHECK-SANITIZE-NEXT: %[[SIGNCHANGECHECK:.*]] = icmp eq i1 false, %[[DST_NEGATIVITYCHECK]], !nosanitize |
27 | // CHECK-SANITIZE-NEXT: %[[ANYEXT:.*]] = sext i8 %[[CONV]] to i32, !nosanitize |
28 | // CHECK-SANITIZE-NEXT: %[[TRUNCHECK:.*]] = icmp eq i32 %[[ANYEXT]], %[[DST]], !nosanitize |
29 | // CHECK-SANITIZE-NEXT: %[[BOTHCHECKS:.*]] = and i1 %[[SIGNCHANGECHECK]], %[[TRUNCHECK]], !nosanitize |
30 | // CHECK-SANITIZE-NEXT: br i1 %[[BOTHCHECKS]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_CONVERSION:[^,]+]],{{.*}} !nosanitize |
31 | // CHECK-SANITIZE: [[HANDLER_IMPLICIT_CONVERSION]]: |
32 | // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTSRC:.*]] = zext i32 %[[DST]] to i64, !nosanitize |
33 | // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTCONV:.*]] = zext i8 %[[CONV]] to i64, !nosanitize |
34 | // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_100_SIGNED_TRUNCATION_OR_SIGN_CHANGE]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTCONV]]){{.*}}, !nosanitize |
35 | // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_100_SIGNED_TRUNCATION_OR_SIGN_CHANGE]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTCONV]]){{.*}}, !nosanitize |
36 | // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize |
37 | // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize |
38 | // CHECK-SANITIZE: [[CONT]]: |
39 | // CHECK-NEXT: ret i8 %[[CONV]] |
40 | // CHECK-NEXT: } |
41 | #line 100 |
42 | return src; |
43 | } |
44 | |
45 | //============================================================================// |
46 | // Truncation sanitizer is disabled per-function. |
47 | //============================================================================// |
48 | |
49 | // CHECK-LABEL: @unsigned_int_to_signed_char__no_truncation_sanitizer |
50 | // CHECK-SAME: (i32 %[[SRC:.*]]) |
51 | __attribute__((no_sanitize("implicit-integer-truncation"))) signed char |
52 | unsigned_int_to_signed_char__no_truncation_sanitizer(unsigned int src) { |
53 | // CHECK-NEXT: [[ENTRY:.*]]: |
54 | // CHECK-NEXT: %[[SRC_ADDR:.*]] = alloca i32 |
55 | // CHECK-NEXT: store i32 %[[SRC]], i32* %[[SRC_ADDR]] |
56 | // CHECK-NEXT: %[[DST:.*]] = load i32, i32* %[[SRC_ADDR]] |
57 | // CHECK-NEXT: %[[CONV:.*]] = trunc i32 %[[DST]] to i8 |
58 | // CHECK-SANITIZE-NEXT: %[[DST_NEGATIVITYCHECK:.*]] = icmp slt i8 %[[CONV]], 0, !nosanitize |
59 | // CHECK-SANITIZE-NEXT: %[[SIGNCHANGECHECK:.*]] = icmp eq i1 false, %[[DST_NEGATIVITYCHECK]], !nosanitize |
60 | // CHECK-SANITIZE-NEXT: br i1 %[[SIGNCHANGECHECK]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_CONVERSION:[^,]+]],{{.*}} !nosanitize |
61 | // CHECK-SANITIZE: [[HANDLER_IMPLICIT_CONVERSION]]: |
62 | // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTSRC:.*]] = zext i32 %[[DST]] to i64, !nosanitize |
63 | // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTCONV:.*]] = zext i8 %[[CONV]] to i64, !nosanitize |
64 | // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_200_SIGN_CHANGE]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTCONV]]){{.*}}, !nosanitize |
65 | // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_200_SIGN_CHANGE]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTCONV]]){{.*}}, !nosanitize |
66 | // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize |
67 | // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize |
68 | // CHECK-SANITIZE: [[CONT]]: |
69 | // CHECK-NEXT: ret i8 %[[CONV]] |
70 | // CHECK-NEXT: } |
71 | #line 200 |
72 | return src; |
73 | } |
74 | |
75 | //============================================================================// |
76 | // Signed truncation sanitizer is disabled per-function. |
77 | //============================================================================// |
78 | |
79 | // CHECK-LABEL: @unsigned_int_to_signed_char__no_signed_truncation_sanitizer |
80 | // CHECK-SAME: (i32 %[[SRC:.*]]) |
81 | __attribute__((no_sanitize("implicit-signed-integer-truncation"))) signed char |
82 | unsigned_int_to_signed_char__no_signed_truncation_sanitizer(unsigned int src) { |
83 | // CHECK-NEXT: [[ENTRY:.*]]: |
84 | // CHECK-NEXT: %[[SRC_ADDR:.*]] = alloca i32 |
85 | // CHECK-NEXT: store i32 %[[SRC]], i32* %[[SRC_ADDR]] |
86 | // CHECK-NEXT: %[[DST:.*]] = load i32, i32* %[[SRC_ADDR]] |
87 | // CHECK-NEXT: %[[CONV:.*]] = trunc i32 %[[DST]] to i8 |
88 | // CHECK-SANITIZE-NEXT: %[[DST_NEGATIVITYCHECK:.*]] = icmp slt i8 %[[CONV]], 0, !nosanitize |
89 | // CHECK-SANITIZE-NEXT: %[[SIGNCHANGECHECK:.*]] = icmp eq i1 false, %[[DST_NEGATIVITYCHECK]], !nosanitize |
90 | // CHECK-SANITIZE-NEXT: br i1 %[[SIGNCHANGECHECK]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_CONVERSION:[^,]+]],{{.*}} !nosanitize |
91 | // CHECK-SANITIZE: [[HANDLER_IMPLICIT_CONVERSION]]: |
92 | // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTSRC:.*]] = zext i32 %[[DST]] to i64, !nosanitize |
93 | // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTCONV:.*]] = zext i8 %[[CONV]] to i64, !nosanitize |
94 | // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_300_SIGN_CHANGE]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTCONV]]){{.*}}, !nosanitize |
95 | // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_300_SIGN_CHANGE]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTCONV]]){{.*}}, !nosanitize |
96 | // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize |
97 | // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize |
98 | // CHECK-SANITIZE: [[CONT]]: |
99 | // CHECK-NEXT: ret i8 %[[CONV]] |
100 | // CHECK-NEXT: } |
101 | #line 300 |
102 | return src; |
103 | } |
104 | |
105 | //============================================================================// |
106 | // Sign change sanitizer is disabled per-function |
107 | //============================================================================// |
108 | |
109 | // CHECK-LABEL: @unsigned_int_to_signed_char__no_sign_change_sanitizer |
110 | // CHECK-SAME: (i32 %[[SRC:.*]]) |
111 | __attribute__((no_sanitize("implicit-integer-sign-change"))) signed char |
112 | unsigned_int_to_signed_char__no_sign_change_sanitizer(unsigned int src) { |
113 | // CHECK-NEXT: [[ENTRY:.*]]: |
114 | // CHECK-NEXT: %[[SRC_ADDR:.*]] = alloca i32 |
115 | // CHECK-NEXT: store i32 %[[SRC]], i32* %[[SRC_ADDR]] |
116 | // CHECK-NEXT: %[[DST:.*]] = load i32, i32* %[[SRC_ADDR]] |
117 | // CHECK-NEXT: %[[CONV:.*]] = trunc i32 %[[DST]] to i8 |
118 | // CHECK-SANITIZE-NEXT: %[[ANYEXT:.*]] = sext i8 %[[CONV]] to i32, !nosanitize |
119 | // CHECK-SANITIZE-NEXT: %[[TRUNCHECK:.*]] = icmp eq i32 %[[ANYEXT]], %[[DST]], !nosanitize |
120 | // CHECK-SANITIZE-NEXT: br i1 %[[TRUNCHECK]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_CONVERSION:[^,]+]],{{.*}} !nosanitize |
121 | // CHECK-SANITIZE: [[HANDLER_IMPLICIT_CONVERSION]]: |
122 | // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTSRC:.*]] = zext i32 %[[DST]] to i64, !nosanitize |
123 | // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTCONV:.*]] = zext i8 %[[CONV]] to i64, !nosanitize |
124 | // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_400_SIGNED_TRUNCATION]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTCONV]]){{.*}}, !nosanitize |
125 | // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_400_SIGNED_TRUNCATION]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTCONV]]){{.*}}, !nosanitize |
126 | // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize |
127 | // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize |
128 | // CHECK-SANITIZE: [[CONT]]: |
129 | // CHECK-NEXT: ret i8 %[[CONV]] |
130 | // CHECK-NEXT: } |
131 | #line 400 |
132 | return src; |
133 | } |
134 | |
135 | //============================================================================// |
136 | // Both sanitizers are disabled per-function. |
137 | //============================================================================// |
138 | |
139 | // CHECK-LABEL: @unsigned_int_to_signed_char__no_sanitizers |
140 | // CHECK-SAME: (i32 %[[SRC:.*]]) |
141 | __attribute__((no_sanitize("implicit-integer-truncation"), |
142 | no_sanitize("implicit-integer-sign-change"))) signed char |
143 | unsigned_int_to_signed_char__no_sanitizers(unsigned int src) { |
144 | // CHECK-NEXT: [[ENTRY:.*]]: |
145 | // CHECK-NEXT: %[[SRC_ADDR:.*]] = alloca i32 |
146 | // CHECK-NEXT: store i32 %[[SRC]], i32* %[[SRC_ADDR]] |
147 | // CHECK-NEXT: %[[DST:.*]] = load i32, i32* %[[SRC_ADDR]] |
148 | // CHECK-NEXT: %[[CONV:.*]] = trunc i32 %[[DST]] to i8 |
149 | // CHECK-NEXT: ret i8 %[[CONV]] |
150 | // CHECK-NEXT: } |
151 | return src; |
152 | } |
153 | |