Clang Project

clang_source_code/test/CodeGen/catch-implicit-integer-truncations.c
1// RUN: %clang_cc1 -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s --check-prefix=CHECK
2// RUN: %clang_cc1 -fsanitize=implicit-unsigned-integer-truncation,implicit-signed-integer-truncation -fno-sanitize-recover=implicit-unsigned-integer-truncation,implicit-signed-integer-truncation -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-unsigned-integer-truncation,implicit-signed-integer-truncation -fsanitize-recover=implicit-unsigned-integer-truncation,implicit-signed-integer-truncation -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-unsigned-integer-truncation,implicit-signed-integer-truncation -fsanitize-trap=implicit-unsigned-integer-truncation,implicit-signed-integer-truncation -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: @[[UNSIGNED_CHAR:.*]] = {{.*}} c"'unsigned char'\00" }
8
9// CHECK-SANITIZE-ANYRECOVER: @[[LINE_100_UNSIGNED_TRUNCATION:.*]] = {{.*}}, i32 100, i32 10 }, {{.*}}* @[[UNSIGNED_INT]], {{.*}}* @[[UNSIGNED_CHAR]], i8 1 }
10// CHECK-SANITIZE-ANYRECOVER: @[[SIGNED_INT:.*]] = {{.*}} c"'int'\00" }
11// CHECK-SANITIZE-ANYRECOVER: @[[LINE_200_SIGNED_TRUNCATION:.*]] = {{.*}}, i32 200, i32 10 }, {{.*}}* @[[SIGNED_INT]], {{.*}}* @[[UNSIGNED_CHAR]], i8 2 }
12// CHECK-SANITIZE-ANYRECOVER: @[[SIGNED_CHAR:.*]] = {{.*}} c"'signed char'\00" }
13// CHECK-SANITIZE-ANYRECOVER: @[[LINE_300_SIGNED_TRUNCATION:.*]] = {{.*}}, i32 300, i32 10 }, {{.*}}* @[[UNSIGNED_INT]], {{.*}}* @[[SIGNED_CHAR]], i8 2 }
14// CHECK-SANITIZE-ANYRECOVER: @[[LINE_400_SIGNED_TRUNCATION:.*]] = {{.*}}, i32 400, i32 10 }, {{.*}}* @[[SIGNED_INT]], {{.*}}* @[[SIGNED_CHAR]], i8 2 }
15
16// CHECK-SANITIZE-ANYRECOVER: @[[UINT32:.*]] = {{.*}} c"'uint32_t' (aka 'unsigned int')\00" }
17// CHECK-SANITIZE-ANYRECOVER: @[[UINT8:.*]] = {{.*}} c"'uint8_t' (aka 'unsigned char')\00" }
18// CHECK-SANITIZE-ANYRECOVER: @[[LINE_500_UNSIGNED_TRUNCATION:.*]] = {{.*}}, i32 500, i32 10 }, {{.*}}* @[[UINT32]], {{.*}}* @[[UINT8]], i8 1 }
19
20// ========================================================================== //
21// The expected true-positives. These are implicit conversions, and they truncate.
22// ========================================================================== //
23
24// CHECK-LABEL: @unsigned_int_to_unsigned_char
25unsigned char unsigned_int_to_unsigned_char(unsigned int src) {
26  // CHECK: %[[DST:.*]] = trunc i32 %[[SRC:.*]] to i8
27  // CHECK-SANITIZE-NEXT: %[[ANYEXT:.*]] = zext i8 %[[DST]] to i32, !nosanitize
28  // CHECK-SANITIZE-NEXT: %[[TRUNCHECK:.*]] = icmp eq i32 %[[ANYEXT]], %[[SRC]], !nosanitize
29  // CHECK-SANITIZE-NEXT: br i1 %[[TRUNCHECK]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_CONVERSION:[^,]+]],{{.*}} !nosanitize
30  // CHECK-SANITIZE: [[HANDLER_IMPLICIT_CONVERSION]]:
31  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTSRC:.*]] = zext i32 %[[SRC]] to i64, !nosanitize
32  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTDST:.*]] = zext i8 %[[DST]] to i64, !nosanitize
33  // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_100_UNSIGNED_TRUNCATION]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
34  // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_100_UNSIGNED_TRUNCATION]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
35  // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize
36  // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize
37  // CHECK-SANITIZE: [[CONT]]:
38  // CHECK-NEXT: ret i8 %[[DST]]
39  // CHECK-NEXT: }
40#line 100
41  return src;
42}
43
44// CHECK-LABEL: @signed_int_to_unsigned_char
45unsigned char signed_int_to_unsigned_char(signed int src) {
46  // CHECK: %[[DST:.*]] = trunc i32 %[[SRC:.*]] to i8
47  // CHECK-SANITIZE-NEXT: %[[ANYEXT:.*]] = zext i8 %[[DST]] to i32, !nosanitize
48  // CHECK-SANITIZE-NEXT: %[[TRUNCHECK:.*]] = icmp eq i32 %[[ANYEXT]], %[[SRC]], !nosanitize
49  // CHECK-SANITIZE-NEXT: br i1 %[[TRUNCHECK]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_CONVERSION:[^,]+]],{{.*}} !nosanitize
50  // CHECK-SANITIZE: [[HANDLER_IMPLICIT_CONVERSION]]:
51  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTSRC:.*]] = zext i32 %[[SRC]] to i64, !nosanitize
52  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTDST:.*]] = zext i8 %[[DST]] to i64, !nosanitize
53  // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_200_SIGNED_TRUNCATION]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
54  // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_200_SIGNED_TRUNCATION]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
55  // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize
56  // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize
57  // CHECK-SANITIZE: [[CONT]]:
58  // CHECK-NEXT: ret i8 %[[DST]]
59  // CHECK-NEXT: }
60#line 200
61  return src;
62}
63
64// CHECK-LABEL: @unsigned_int_to_signed_char
65signed char unsigned_int_to_signed_char(unsigned int src) {
66  // CHECK: %[[DST:.*]] = trunc i32 %[[SRC:.*]] to i8
67  // CHECK-SANITIZE-NEXT: %[[ANYEXT:.*]] = sext i8 %[[DST]] to i32, !nosanitize
68  // CHECK-SANITIZE-NEXT: %[[TRUNCHECK:.*]] = icmp eq i32 %[[ANYEXT]], %[[SRC]], !nosanitize
69  // CHECK-SANITIZE-NEXT: br i1 %[[TRUNCHECK]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_CONVERSION:[^,]+]],{{.*}} !nosanitize
70  // CHECK-SANITIZE: [[HANDLER_IMPLICIT_CONVERSION]]:
71  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTSRC:.*]] = zext i32 %[[SRC]] to i64, !nosanitize
72  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTDST:.*]] = zext i8 %[[DST]] to i64, !nosanitize
73  // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_300_SIGNED_TRUNCATION]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
74  // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_300_SIGNED_TRUNCATION]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
75  // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize
76  // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize
77  // CHECK-SANITIZE: [[CONT]]:
78  // CHECK-NEXT: ret i8 %[[DST]]
79  // CHECK-NEXT: }
80#line 300
81  return src;
82}
83
84// CHECK-LABEL: @signed_int_to_signed_char
85signed char signed_int_to_signed_char(signed int src) {
86  // CHECK: %[[DST:.*]] = trunc i32 %[[SRC:.*]] to i8
87  // CHECK-SANITIZE-NEXT: %[[ANYEXT:.*]] = sext i8 %[[DST]] to i32, !nosanitize
88  // CHECK-SANITIZE-NEXT: %[[TRUNCHECK:.*]] = icmp eq i32 %[[ANYEXT]], %[[SRC]], !nosanitize
89  // CHECK-SANITIZE-NEXT: br i1 %[[TRUNCHECK]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_CONVERSION:[^,]+]],{{.*}} !nosanitize
90  // CHECK-SANITIZE: [[HANDLER_IMPLICIT_CONVERSION]]:
91  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTSRC:.*]] = zext i32 %[[SRC]] to i64, !nosanitize
92  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTDST:.*]] = zext i8 %[[DST]] to i64, !nosanitize
93  // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_400_SIGNED_TRUNCATION]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
94  // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_400_SIGNED_TRUNCATION]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
95  // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize
96  // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize
97  // CHECK-SANITIZE: [[CONT]]:
98  // CHECK-NEXT: ret i8 %[[DST]]
99  // CHECK-NEXT: }
100#line 400
101  return src;
102}
103
104// ========================================================================== //
105// Check canonical type stuff
106// ========================================================================== //
107
108typedef unsigned int uint32_t;
109typedef unsigned char uint8_t;
110
111// CHECK-LABEL: @uint32_to_uint8
112uint8_t uint32_to_uint8(uint32_t src) {
113  // CHECK: %[[DST:.*]] = trunc i32 %[[SRC:.*]] to i8
114  // CHECK-SANITIZE-NEXT: %[[ANYEXT:.*]] = zext i8 %[[DST]] to i32, !nosanitize
115  // CHECK-SANITIZE-NEXT: %[[TRUNCHECK:.*]] = icmp eq i32 %[[ANYEXT]], %[[SRC]], !nosanitize
116  // CHECK-SANITIZE-NEXT: br i1 %[[TRUNCHECK]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_CONVERSION:[^,]+]],{{.*}} !nosanitize
117  // CHECK-SANITIZE: [[HANDLER_IMPLICIT_CONVERSION]]:
118  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTSRC:.*]] = zext i32 %[[SRC]] to i64, !nosanitize
119  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTDST:.*]] = zext i8 %[[DST]] to i64, !nosanitize
120  // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_500_UNSIGNED_TRUNCATION]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
121  // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_500_UNSIGNED_TRUNCATION]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
122  // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize
123  // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize
124  // CHECK-SANITIZE: [[CONT]]:
125  // CHECK-NEXT: ret i8 %[[DST]]
126  // CHECK-NEXT: }
127#line 500
128  return src;
129}
130
131// ========================================================================== //
132// Check that explicit conversion does not interfere with implicit conversion
133// ========================================================================== //
134// These contain one implicit truncating conversion, and one explicit truncating conversion.
135// We want to make sure that we still diagnose the implicit conversion.
136
137// Implicit truncation after explicit truncation.
138// CHECK-LABEL: @explicit_conversion_interference0
139unsigned char explicit_conversion_interference0(unsigned int c) {
140  // CHECK-SANITIZE: %[[ANYEXT:.*]] = zext i8 %[[DST:.*]] to i16, !nosanitize
141  // CHECK-SANITIZE: call
142  return (unsigned short)c;
143}
144
145// Implicit truncation before explicit truncation.
146// CHECK-LABEL: @explicit_conversion_interference1
147unsigned char explicit_conversion_interference1(unsigned int c) {
148  // CHECK-SANITIZE: %[[ANYEXT:.*]] = zext i16 %[[DST:.*]] to i32, !nosanitize
149  // CHECK-SANITIZE: call
150  unsigned short b;
151  return (unsigned char)(b = c);
152}
153
154// ========================================================================== //
155// The expected true-negatives.
156// ========================================================================== //
157
158// Sanitization is explicitly disabled.
159// ========================================================================== //
160
161// CHECK-LABEL: @blacklist_0
162__attribute__((no_sanitize("undefined"))) unsigned char blacklist_0(unsigned int src) {
163  // We are not in "undefined" group, so that doesn't work.
164  // CHECK-SANITIZE: call
165  return src;
166}
167
168// CHECK-LABEL: @blacklist_1
169__attribute__((no_sanitize("integer"))) unsigned char blacklist_1(unsigned int src) {
170  return src;
171}
172
173// CHECK-LABEL: @blacklist_2
174__attribute__((no_sanitize("implicit-conversion"))) unsigned char blacklist_2(unsigned int src) {
175  return src;
176}
177
178// CHECK-LABEL: @blacklist_3
179__attribute__((no_sanitize("implicit-integer-truncation"))) unsigned char blacklist_3(unsigned int src) {
180  return src;
181}
182
183// Explicit truncating conversions.
184// ========================================================================== //
185
186// CHECK-LABEL: @explicit_unsigned_int_to_unsigned_char
187unsigned char explicit_unsigned_int_to_unsigned_char(unsigned int src) {
188  return (unsigned char)src;
189}
190
191// CHECK-LABEL: @explicit_signed_int_to_unsigned_char
192unsigned char explicit_signed_int_to_unsigned_char(signed int src) {
193  return (unsigned char)src;
194}
195
196// CHECK-LABEL: @explicit_unsigned_int_to_signed_char
197signed char explicit_unsigned_int_to_signed_char(unsigned int src) {
198  return (signed char)src;
199}
200
201// CHECK-LABEL: @explicit_signed_int_to_signed_char
202signed char explicit_signed_int_to_signed_char(signed int src) {
203  return (signed char)src;
204}
205
206// Explicit NOP conversions.
207// ========================================================================== //
208
209// CHECK-LABEL: @explicit_unsigned_int_to_unsigned_int
210unsigned int explicit_unsigned_int_to_unsigned_int(unsigned int src) {
211  return (unsigned int)src;
212}
213
214// CHECK-LABEL: @explicit_signed_int_to_signed_int
215signed int explicit_signed_int_to_signed_int(signed int src) {
216  return (signed int)src;
217}
218
219// CHECK-LABEL: @explicit_unsigned_char_to_signed_char
220unsigned char explicit_unsigned_char_to_signed_char(unsigned char src) {
221  return (unsigned char)src;
222}
223
224// CHECK-LABEL: @explicit_signed_char_to_signed_char
225signed char explicit_signed_char_to_signed_char(signed char src) {
226  return (signed char)src;
227}
228
229// upcasts.
230// ========================================================================== //
231
232// CHECK-LABEL: @unsigned_char_to_unsigned_int
233unsigned int unsigned_char_to_unsigned_int(unsigned char src) {
234  return src;
235}
236
237// CHECK-LABEL: @signed_char_to_unsigned_int
238unsigned int signed_char_to_unsigned_int(signed char src) {
239  return src;
240}
241
242// CHECK-LABEL: @unsigned_char_to_signed_int
243signed int unsigned_char_to_signed_int(unsigned char src) {
244  return src;
245}
246
247// CHECK-LABEL: @signed_char_to_signed_int
248signed int signed_char_to_signed_int(signed char src) {
249  return src;
250}
251
252// Explicit upcasts.
253// ========================================================================== //
254
255// CHECK-LABEL: @explicit_unsigned_char_to_unsigned_int
256unsigned int explicit_unsigned_char_to_unsigned_int(unsigned char src) {
257  return (unsigned int)src;
258}
259
260// CHECK-LABEL: @explicit_signed_char_to_unsigned_int
261unsigned int explicit_signed_char_to_unsigned_int(signed char src) {
262  return (unsigned int)src;
263}
264
265// CHECK-LABEL: @explicit_unsigned_char_to_signed_int
266signed int explicit_unsigned_char_to_signed_int(unsigned char src) {
267  return (signed int)src;
268}
269
270// CHECK-LABEL: @explicit_signed_char_to_signed_int
271signed int explicit_signed_char_to_signed_int(signed char src) {
272  return (signed int)src;
273}
274
275// conversions to to boolean type are not counted as truncation.
276// ========================================================================== //
277
278// CHECK-LABEL: @unsigned_int_to_bool
279_Bool unsigned_int_to_bool(unsigned int src) {
280  return src;
281}
282
283// CHECK-LABEL: @signed_int_to_bool
284_Bool signed_int_to_bool(signed int src) {
285  return src;
286}
287
288// CHECK-LABEL: @explicit_unsigned_int_to_bool
289_Bool explicit_unsigned_int_to_bool(unsigned int src) {
290  return (_Bool)src;
291}
292
293// CHECK-LABEL: @explicit_signed_int_to_bool
294_Bool explicit_signed_int_to_bool(signed int src) {
295  return (_Bool)src;
296}
297
298// Explicit truncating conversions from pointer to a much-smaller integer.
299// Can not have an implicit conversion from pointer to an integer.
300// Can not have an implicit conversion between two enums.
301// ========================================================================== //
302
303// CHECK-LABEL: @explicit_voidptr_to_unsigned_char
304unsigned char explicit_voidptr_to_unsigned_char(void *src) {
305  return (unsigned char)src;
306}
307
308// CHECK-LABEL: @explicit_voidptr_to_signed_char
309signed char explicit_voidptr_to_signed_char(void *src) {
310  return (signed char)src;
311}
312
313// Implicit truncating conversions from floating-point may result in precision loss.
314// ========================================================================== //
315
316// CHECK-LABEL: @float_to_unsigned_int
317unsigned int float_to_unsigned_int(float src) {
318  return src;
319}
320
321// CHECK-LABEL: @float_to_signed_int
322signed int float_to_signed_int(float src) {
323  return src;
324}
325
326// CHECK-LABEL: @double_to_unsigned_int
327unsigned int double_to_unsigned_int(double src) {
328  return src;
329}
330
331// CHECK-LABEL: @double_to_signed_int
332signed int double_to_signed_int(double src) {
333  return src;
334}
335
336// Implicit truncating conversions between fp may result in precision loss.
337// ========================================================================== //
338
339// CHECK-LABEL: @double_to_float
340float double_to_float(double src) {
341  return src;
342}
343