diff options
Diffstat (limited to 'clang/test')
9 files changed, 1158 insertions, 14 deletions
diff --git a/clang/test/CodeGen/catch-implicit-conversions-basics.c b/clang/test/CodeGen/catch-implicit-conversions-basics.c new file mode 100644 index 00000000000..2af16e80c8f --- /dev/null +++ b/clang/test/CodeGen/catch-implicit-conversions-basics.c @@ -0,0 +1,125 @@ +// RUN: %clang_cc1 -fsanitize=implicit-unsigned-integer-truncation,implicit-signed-integer-truncation,implicit-integer-sign-change -fsanitize-recover=implicit-unsigned-integer-truncation,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 + +// Test plan: +// * Two types - int and char +// * Two signs - signed and unsigned +// * Square that - we have input and output types. +// Thus, there are total of (2*2)^2 == 16 tests. +// These are all the possible variations/combinations of casts. +// However, not all of them should result in the check. +// So here, we *only* check which should and which should not result in checks. + +// CHECK-DAG: @[[LINE_500_UNSIGNED_TRUNCATION:.*]] = {{.*}}, i32 500, i32 10 }, {{.*}}, {{.*}}, i8 1 } +// CHECK-DAG: @[[LINE_900_SIGN_CHANGE:.*]] = {{.*}}, i32 900, i32 10 }, {{.*}}, {{.*}}, i8 3 } +// CHECK-DAG: @[[LINE_1000_SIGN_CHANGE:.*]] = {{.*}}, i32 1000, i32 10 }, {{.*}}, {{.*}}, i8 3 } +// CHECK-DAG: @[[LINE_1100_SIGNED_TRUNCATION:.*]] = {{.*}}, i32 1100, i32 10 }, {{.*}}, {{.*}}, i8 2 } +// CHECK-DAG: @[[LINE_1200_SIGN_CHANGE:.*]] = {{.*}}, i32 1200, i32 10 }, {{.*}}, {{.*}}, i8 3 } +// CHECK-DAG: @[[LINE_1300_SIGN_CHANGE:.*]] = {{.*}}, i32 1300, i32 10 }, {{.*}}, {{.*}}, i8 3 } +// CHECK-DAG: @[[LINE_1400_SIGN_CHANGE:.*]] = {{.*}}, i32 1400, i32 10 }, {{.*}}, {{.*}}, i8 3 } +// CHECK-DAG: @[[LINE_1500_SIGNED_TRUNCATION_OR_SIGN_CHANGE:.*]] = {{.*}}, i32 1500, i32 10 }, {{.*}}, {{.*}}, i8 4 } +// CHECK-DAG: @[[LINE_1600_SIGNED_TRUNCATION:.*]] = {{.*}}, i32 1600, i32 10 }, {{.*}}, {{.*}}, i8 2 } + +// CHECK-LABEL: @convert_unsigned_int_to_unsigned_int +unsigned int convert_unsigned_int_to_unsigned_int(unsigned int x) { +#line 100 + return x; +} + +// CHECK-LABEL: @convert_unsigned_char_to_unsigned_char +unsigned char convert_unsigned_char_to_unsigned_char(unsigned char x) { +#line 200 + return x; +} + +// CHECK-LABEL: @convert_signed_int_to_signed_int +signed int convert_signed_int_to_signed_int(signed int x) { +#line 300 + return x; +} + +// CHECK-LABEL: @convert_signed_char_to_signed_char +signed char convert_signed_char_to_signed_char(signed char x) { +#line 400 + return x; +} + +// CHECK-LABEL: @convert_unsigned_int_to_unsigned_char +unsigned char convert_unsigned_int_to_unsigned_char(unsigned int x) { + // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_500_UNSIGNED_TRUNCATION]] to i8*) +#line 500 + return x; +} + +// CHECK-LABEL: @convert_unsigned_char_to_unsigned_int +unsigned int convert_unsigned_char_to_unsigned_int(unsigned char x) { +#line 600 + return x; +} + +// CHECK-LABEL: @convert_unsigned_char_to_signed_int +signed int convert_unsigned_char_to_signed_int(unsigned char x) { +#line 700 + return x; +} + +// CHECK-LABEL: @convert_signed_char_to_signed_int +signed int convert_signed_char_to_signed_int(signed char x) { +#line 800 + return x; +} + +// CHECK-LABEL: @convert_unsigned_int_to_signed_int +signed int convert_unsigned_int_to_signed_int(unsigned int x) { + // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_900_SIGN_CHANGE]] to i8*) +#line 900 + return x; +} + +// CHECK-LABEL: @convert_signed_int_to_unsigned_int +unsigned int convert_signed_int_to_unsigned_int(signed int x) { + // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1000_SIGN_CHANGE]] to i8*) +#line 1000 + return x; +} + +// CHECK-LABEL: @convert_signed_int_to_unsigned_char +unsigned char convert_signed_int_to_unsigned_char(signed int x) { + // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1100_SIGNED_TRUNCATION]] to i8*) +#line 1100 + return x; +} + +// CHECK-LABEL: @convert_signed_char_to_unsigned_char +unsigned char convert_signed_char_to_unsigned_char(signed char x) { + // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1200_SIGN_CHANGE]] to i8*) +#line 1200 + return x; +} + +// CHECK-LABEL: @convert_unsigned_char_to_signed_char +signed char convert_unsigned_char_to_signed_char(unsigned char x) { + // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1300_SIGN_CHANGE]] to i8*) +#line 1300 + return x; +} + +// CHECK-LABEL: @convert_signed_char_to_unsigned_int +unsigned int convert_signed_char_to_unsigned_int(signed char x) { + // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1400_SIGN_CHANGE]] to i8*) +#line 1400 + return x; +} + +// CHECK-LABEL: @convert_unsigned_int_to_signed_char +signed char convert_unsigned_int_to_signed_char(unsigned int x) { + // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1500_SIGNED_TRUNCATION_OR_SIGN_CHANGE]] to i8*) +#line 1500 + return x; +} + +// CHECK-LABEL: @convert_signed_int_to_signed_char +signed char convert_signed_int_to_signed_char(signed int x) { + // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1600_SIGNED_TRUNCATION]] to i8*) +#line 1600 + return x; +} diff --git a/clang/test/CodeGen/catch-implicit-integer-arithmetic-value-change-basics.c b/clang/test/CodeGen/catch-implicit-integer-arithmetic-value-change-basics.c new file mode 100644 index 00000000000..0ba16eb052a --- /dev/null +++ b/clang/test/CodeGen/catch-implicit-integer-arithmetic-value-change-basics.c @@ -0,0 +1,123 @@ +// 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 + +// Test plan: +// * Two types - int and char +// * Two signs - signed and unsigned +// * Square that - we have input and output types. +// Thus, there are total of (2*2)^2 == 16 tests. +// These are all the possible variations/combinations of casts. +// However, not all of them should result in the check. +// So here, we *only* check which should and which should not result in checks. + +// CHECK-DAG: @[[LINE_900_SIGN_CHANGE:.*]] = {{.*}}, i32 900, i32 10 }, {{.*}}, {{.*}}, i8 3 } +// CHECK-DAG: @[[LINE_1000_SIGN_CHANGE:.*]] = {{.*}}, i32 1000, i32 10 }, {{.*}}, {{.*}}, i8 3 } +// CHECK-DAG: @[[LINE_1100_SIGNED_TRUNCATION:.*]] = {{.*}}, i32 1100, i32 10 }, {{.*}}, {{.*}}, i8 2 } +// CHECK-DAG: @[[LINE_1200_SIGN_CHANGE:.*]] = {{.*}}, i32 1200, i32 10 }, {{.*}}, {{.*}}, i8 3 } +// CHECK-DAG: @[[LINE_1300_SIGN_CHANGE:.*]] = {{.*}}, i32 1300, i32 10 }, {{.*}}, {{.*}}, i8 3 } +// CHECK-DAG: @[[LINE_1400_SIGN_CHANGE:.*]] = {{.*}}, i32 1400, i32 10 }, {{.*}}, {{.*}}, i8 3 } +// CHECK-DAG: @[[LINE_1500_SIGNED_TRUNCATION_OR_SIGN_CHANGE:.*]] = {{.*}}, i32 1500, i32 10 }, {{.*}}, {{.*}}, i8 4 } +// CHECK-DAG: @[[LINE_1600_SIGNED_TRUNCATION:.*]] = {{.*}}, i32 1600, i32 10 }, {{.*}}, {{.*}}, i8 2 } + +// CHECK-LABEL: @convert_unsigned_int_to_unsigned_int +unsigned int convert_unsigned_int_to_unsigned_int(unsigned int x) { +#line 100 + return x; +} + +// CHECK-LABEL: @convert_unsigned_char_to_unsigned_char +unsigned char convert_unsigned_char_to_unsigned_char(unsigned char x) { +#line 200 + return x; +} + +// CHECK-LABEL: @convert_signed_int_to_signed_int +signed int convert_signed_int_to_signed_int(signed int x) { +#line 300 + return x; +} + +// CHECK-LABEL: @convert_signed_char_to_signed_char +signed char convert_signed_char_to_signed_char(signed char x) { +#line 400 + return x; +} + +// CHECK-LABEL: @convert_unsigned_int_to_unsigned_char +unsigned char convert_unsigned_int_to_unsigned_char(unsigned int x) { +#line 500 + return x; +} + +// CHECK-LABEL: @convert_unsigned_char_to_unsigned_int +unsigned int convert_unsigned_char_to_unsigned_int(unsigned char x) { +#line 600 + return x; +} + +// CHECK-LABEL: @convert_unsigned_char_to_signed_int +signed int convert_unsigned_char_to_signed_int(unsigned char x) { +#line 700 + return x; +} + +// CHECK-LABEL: @convert_signed_char_to_signed_int +signed int convert_signed_char_to_signed_int(signed char x) { +#line 800 + return x; +} + +// CHECK-LABEL: @convert_unsigned_int_to_signed_int +signed int convert_unsigned_int_to_signed_int(unsigned int x) { + // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_900_SIGN_CHANGE]] to i8*) +#line 900 + return x; +} + +// CHECK-LABEL: @convert_signed_int_to_unsigned_int +unsigned int convert_signed_int_to_unsigned_int(signed int x) { + // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1000_SIGN_CHANGE]] to i8*) +#line 1000 + return x; +} + +// CHECK-LABEL: @convert_signed_int_to_unsigned_char +unsigned char convert_signed_int_to_unsigned_char(signed int x) { + // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1100_SIGNED_TRUNCATION]] to i8*) +#line 1100 + return x; +} + +// CHECK-LABEL: @convert_signed_char_to_unsigned_char +unsigned char convert_signed_char_to_unsigned_char(signed char x) { + // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1200_SIGN_CHANGE]] to i8*) +#line 1200 + return x; +} + +// CHECK-LABEL: @convert_unsigned_char_to_signed_char +signed char convert_unsigned_char_to_signed_char(unsigned char x) { + // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1300_SIGN_CHANGE]] to i8*) +#line 1300 + return x; +} + +// CHECK-LABEL: @convert_signed_char_to_unsigned_int +unsigned int convert_signed_char_to_unsigned_int(signed char x) { + // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1400_SIGN_CHANGE]] to i8*) +#line 1400 + return x; +} + +// CHECK-LABEL: @convert_unsigned_int_to_signed_char +signed char convert_unsigned_int_to_signed_char(unsigned int x) { + // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1500_SIGNED_TRUNCATION_OR_SIGN_CHANGE]] to i8*) +#line 1500 + return x; +} + +// CHECK-LABEL: @convert_signed_int_to_signed_char +signed char convert_signed_int_to_signed_char(signed int x) { + // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1600_SIGNED_TRUNCATION]] to i8*) +#line 1600 + return x; +} diff --git a/clang/test/CodeGen/catch-implicit-integer-conversions-basics.c b/clang/test/CodeGen/catch-implicit-integer-conversions-basics.c index 1a34246d78b..2af16e80c8f 100644 --- a/clang/test/CodeGen/catch-implicit-integer-conversions-basics.c +++ b/clang/test/CodeGen/catch-implicit-integer-conversions-basics.c @@ -1,4 +1,4 @@ -// 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 +// RUN: %clang_cc1 -fsanitize=implicit-unsigned-integer-truncation,implicit-signed-integer-truncation,implicit-integer-sign-change -fsanitize-recover=implicit-unsigned-integer-truncation,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 // Test plan: // * Two types - int and char @@ -10,8 +10,13 @@ // So here, we *only* check which should and which should not result in checks. // CHECK-DAG: @[[LINE_500_UNSIGNED_TRUNCATION:.*]] = {{.*}}, i32 500, i32 10 }, {{.*}}, {{.*}}, i8 1 } +// CHECK-DAG: @[[LINE_900_SIGN_CHANGE:.*]] = {{.*}}, i32 900, i32 10 }, {{.*}}, {{.*}}, i8 3 } +// CHECK-DAG: @[[LINE_1000_SIGN_CHANGE:.*]] = {{.*}}, i32 1000, i32 10 }, {{.*}}, {{.*}}, i8 3 } // CHECK-DAG: @[[LINE_1100_SIGNED_TRUNCATION:.*]] = {{.*}}, i32 1100, i32 10 }, {{.*}}, {{.*}}, i8 2 } -// CHECK-DAG: @[[LINE_1500_SIGNED_TRUNCATION:.*]] = {{.*}}, i32 1500, i32 10 }, {{.*}}, {{.*}}, i8 2 } +// CHECK-DAG: @[[LINE_1200_SIGN_CHANGE:.*]] = {{.*}}, i32 1200, i32 10 }, {{.*}}, {{.*}}, i8 3 } +// CHECK-DAG: @[[LINE_1300_SIGN_CHANGE:.*]] = {{.*}}, i32 1300, i32 10 }, {{.*}}, {{.*}}, i8 3 } +// CHECK-DAG: @[[LINE_1400_SIGN_CHANGE:.*]] = {{.*}}, i32 1400, i32 10 }, {{.*}}, {{.*}}, i8 3 } +// CHECK-DAG: @[[LINE_1500_SIGNED_TRUNCATION_OR_SIGN_CHANGE:.*]] = {{.*}}, i32 1500, i32 10 }, {{.*}}, {{.*}}, i8 4 } // CHECK-DAG: @[[LINE_1600_SIGNED_TRUNCATION:.*]] = {{.*}}, i32 1600, i32 10 }, {{.*}}, {{.*}}, i8 2 } // CHECK-LABEL: @convert_unsigned_int_to_unsigned_int @@ -65,12 +70,14 @@ signed int convert_signed_char_to_signed_int(signed char x) { // CHECK-LABEL: @convert_unsigned_int_to_signed_int signed int convert_unsigned_int_to_signed_int(unsigned int x) { + // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_900_SIGN_CHANGE]] to i8*) #line 900 return x; } // CHECK-LABEL: @convert_signed_int_to_unsigned_int unsigned int convert_signed_int_to_unsigned_int(signed int x) { + // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1000_SIGN_CHANGE]] to i8*) #line 1000 return x; } @@ -84,25 +91,28 @@ unsigned char convert_signed_int_to_unsigned_char(signed int x) { // CHECK-LABEL: @convert_signed_char_to_unsigned_char unsigned char convert_signed_char_to_unsigned_char(signed char x) { + // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1200_SIGN_CHANGE]] to i8*) #line 1200 return x; } // CHECK-LABEL: @convert_unsigned_char_to_signed_char signed char convert_unsigned_char_to_signed_char(unsigned char x) { + // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1300_SIGN_CHANGE]] to i8*) #line 1300 return x; } // CHECK-LABEL: @convert_signed_char_to_unsigned_int unsigned int convert_signed_char_to_unsigned_int(signed char x) { + // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1400_SIGN_CHANGE]] to i8*) #line 1400 return x; } // CHECK-LABEL: @convert_unsigned_int_to_signed_char signed char convert_unsigned_int_to_signed_char(unsigned int x) { - // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1500_SIGNED_TRUNCATION]] to i8*) + // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1500_SIGNED_TRUNCATION_OR_SIGN_CHANGE]] to i8*) #line 1500 return x; } diff --git a/clang/test/CodeGen/catch-implicit-integer-sign-changes-basics.c b/clang/test/CodeGen/catch-implicit-integer-sign-changes-basics.c new file mode 100644 index 00000000000..71533a9b924 --- /dev/null +++ b/clang/test/CodeGen/catch-implicit-integer-sign-changes-basics.c @@ -0,0 +1,157 @@ +// RUN: %clang_cc1 -fsanitize=implicit-integer-sign-change -fsanitize-recover=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 + +// Test plan: +// * Two types - int and char +// * Two signs - signed and unsigned +// * Square that - we have input and output types. +// Thus, there are total of (2*2)^2 == 16 tests. +// These are all the possible variations/combinations of casts. +// However, not all of them should result in the check. +// So here, we *only* check which should and which should not result in checks. + +// CHECK-DAG: @[[LINE_900_SIGN_CHANGE:.*]] = {{.*}}, i32 900, i32 10 }, {{.*}}, {{.*}}, i8 3 } +// CHECK-DAG: @[[LINE_1000_SIGN_CHANGE:.*]] = {{.*}}, i32 1000, i32 10 }, {{.*}}, {{.*}}, i8 3 } +// CHECK-DAG: @[[LINE_1100_SIGN_CHANGE:.*]] = {{.*}}, i32 1100, i32 10 }, {{.*}}, {{.*}}, i8 3 } +// CHECK-DAG: @[[LINE_1200_SIGN_CHANGE:.*]] = {{.*}}, i32 1200, i32 10 }, {{.*}}, {{.*}}, i8 3 } +// CHECK-DAG: @[[LINE_1300_SIGN_CHANGE:.*]] = {{.*}}, i32 1300, i32 10 }, {{.*}}, {{.*}}, i8 3 } +// CHECK-DAG: @[[LINE_1400_SIGN_CHANGE:.*]] = {{.*}}, i32 1400, i32 10 }, {{.*}}, {{.*}}, i8 3 } +// CHECK-DAG: @[[LINE_1500_SIGN_CHANGE:.*]] = {{.*}}, i32 1500, i32 10 }, {{.*}}, {{.*}}, i8 3 } +// CHECK-DAG: @[[LINE_1600_SIGN_CHANGE:.*]] = {{.*}}, i32 1600, i32 10 }, {{.*}}, {{.*}}, i8 3 } + +//============================================================================// +// Half of the cases do not need the check. // +//============================================================================// + +//----------------------------------------------------------------------------// +// No cast happens at all. No check needed. +//----------------------------------------------------------------------------// + +// CHECK-LABEL: @convert_unsigned_int_to_unsigned_int +unsigned int convert_unsigned_int_to_unsigned_int(unsigned int x) { +#line 100 + return x; +} + +// CHECK-LABEL: @convert_unsigned_char_to_unsigned_char +unsigned char convert_unsigned_char_to_unsigned_char(unsigned char x) { +#line 200 + return x; +} + +// CHECK-LABEL: @convert_signed_int_to_signed_int +signed int convert_signed_int_to_signed_int(signed int x) { +#line 300 + return x; +} + +// CHECK-LABEL: @convert_signed_char_to_signed_char +signed char convert_signed_char_to_signed_char(signed char x) { +#line 400 + return x; +} + +//----------------------------------------------------------------------------// +// Both types are unsigned. No check needed. +//----------------------------------------------------------------------------// + +// CHECK-LABEL: @convert_unsigned_int_to_unsigned_char +unsigned char convert_unsigned_int_to_unsigned_char(unsigned int x) { +#line 500 + return x; +} + +// CHECK-LABEL: @convert_unsigned_char_to_unsigned_int +unsigned int convert_unsigned_char_to_unsigned_int(unsigned char x) { +#line 600 + return x; +} + +//----------------------------------------------------------------------------// +// Source type was unsigned, destination type is signed, but non-negative. +// Because zero-extension happens - the sign bit will be 0. No check needed. +//----------------------------------------------------------------------------// + +// CHECK-LABEL: @convert_unsigned_char_to_signed_int +signed int convert_unsigned_char_to_signed_int(unsigned char x) { +#line 700 + return x; +} + +//----------------------------------------------------------------------------// +// Both types are signed, and have the same sign, since sign-extension happens, +// i.e. the sign bit will be propagated. No check needed. +//----------------------------------------------------------------------------// + +// CHECK-LABEL: @convert_signed_char_to_signed_int +signed int convert_signed_char_to_signed_int(signed char x) { +#line 800 + return x; +} + +//============================================================================// +// The remaining 8 cases *do* need the check. // +//============================================================================// + +// These 3 result in simple 'icmp sge i32 %x, 0' + +// CHECK-LABEL: @convert_unsigned_int_to_signed_int +signed int convert_unsigned_int_to_signed_int(unsigned int x) { + // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_900_SIGN_CHANGE]] to i8*) +#line 900 + return x; +} + +// CHECK-LABEL: @convert_signed_int_to_unsigned_int +unsigned int convert_signed_int_to_unsigned_int(signed int x) { + // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1000_SIGN_CHANGE]] to i8*) +#line 1000 + return x; +} + +// CHECK-LABEL: @convert_signed_int_to_unsigned_char +unsigned char convert_signed_int_to_unsigned_char(signed int x) { + // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1100_SIGN_CHANGE]] to i8*) +#line 1100 + return x; +} + +// These 3 result in simple 'icmp sge i8 %x, 0' + +// CHECK-LABEL: @convert_signed_char_to_unsigned_char +unsigned char convert_signed_char_to_unsigned_char(signed char x) { + // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1200_SIGN_CHANGE]] to i8*) +#line 1200 + return x; +} + +// CHECK-LABEL: @convert_unsigned_char_to_signed_char +signed char convert_unsigned_char_to_signed_char(unsigned char x) { + // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1300_SIGN_CHANGE]] to i8*) +#line 1300 + return x; +} + +// CHECK-LABEL: @convert_signed_char_to_unsigned_int +unsigned int convert_signed_char_to_unsigned_int(signed char x) { + // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1400_SIGN_CHANGE]] to i8*) +#line 1400 + return x; +} + +// 'icmp sge i8 (trunc i32 %x), 0' + +// CHECK-LABEL: @convert_unsigned_int_to_signed_char +signed char convert_unsigned_int_to_signed_char(unsigned int x) { + // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1500_SIGN_CHANGE]] to i8*) +#line 1500 + return x; +} + +// 'xor i1 (icmp sge i8 (trunc i32 %x), 0), (icmp sge i32 %x, 0)' + +// CHECK-LABEL: @convert_signed_int_to_signed_char +signed char convert_signed_int_to_signed_char(signed int x) { + // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1600_SIGN_CHANGE]] to i8*) +#line 1600 + return x; +} diff --git a/clang/test/CodeGen/catch-implicit-integer-sign-changes-true-negatives.c b/clang/test/CodeGen/catch-implicit-integer-sign-changes-true-negatives.c new file mode 100644 index 00000000000..3798cccdd53 --- /dev/null +++ b/clang/test/CodeGen/catch-implicit-integer-sign-changes-true-negatives.c @@ -0,0 +1,140 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s -implicit-check-not="call void @__ubsan_handle_implicit_conversion" --check-prefix=CHECK +// RUN: %clang_cc1 -fsanitize=implicit-integer-sign-change -fno-sanitize-recover=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 +// RUN: %clang_cc1 -fsanitize=implicit-integer-sign-change -fsanitize-recover=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 +// RUN: %clang_cc1 -fsanitize=implicit-integer-sign-change -fsanitize-trap=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 + +// ========================================================================== // +// The expected true-negatives. +// ========================================================================== // + +// Sanitization is explicitly disabled. +// ========================================================================== // + +// CHECK-LABEL: @blacklist_0 +__attribute__((no_sanitize("undefined"))) unsigned int blacklist_0(signed int src) { + // We are not in "undefined" group, so that doesn't work. + // CHECK-SANITIZE: call + return src; +} + +// CHECK-LABEL: @blacklist_1 +__attribute__((no_sanitize("integer"))) unsigned int blacklist_1(signed int src) { + return src; +} + +// CHECK-LABEL: @blacklist_2 +__attribute__((no_sanitize("implicit-conversion"))) unsigned int blacklist_2(signed int src) { + return src; +} + +// CHECK-LABEL: @blacklist_3 +__attribute__((no_sanitize("implicit-integer-sign-change"))) unsigned int blacklist_3(signed int src) { + return src; +} + +// Explicit sign-changing conversions. +// ========================================================================== // + +// CHECK-LABEL: explicit_signed_int_to_unsigned_int +unsigned int explicit_signed_int_to_unsigned_int(signed int src) { + return (unsigned int)src; +} + +// CHECK-LABEL: explicit_unsigned_int_to_signed_int +signed int explicit_unsigned_int_to_signed_int(unsigned int src) { + return (signed int)src; +} + +// Explicit NOP conversions. +// ========================================================================== // + +// CHECK-LABEL: @explicit_ununsigned_int_to_ununsigned_int +unsigned int explicit_ununsigned_int_to_ununsigned_int(unsigned int src) { + return (unsigned int)src; +} + +// CHECK-LABEL: @explicit_unsigned_int_to_unsigned_int +signed int explicit_unsigned_int_to_unsigned_int(signed int src) { + return (signed int)src; +} + +// conversions to to boolean type are not counted as sign-change. +// ========================================================================== // + +// CHECK-LABEL: @unsigned_int_to_bool +_Bool unsigned_int_to_bool(unsigned int src) { + return src; +} + +// CHECK-LABEL: @signed_int_to_bool +_Bool signed_int_to_bool(signed int src) { + return src; +} + +// CHECK-LABEL: @explicit_unsigned_int_to_bool +_Bool explicit_unsigned_int_to_bool(unsigned int src) { + return (_Bool)src; +} + +// CHECK-LABEL: @explicit_signed_int_to_bool +_Bool explicit_signed_int_to_bool(signed int src) { + return (_Bool)src; +} + +// Explicit conversions from pointer to an integer. +// Can not have an implicit conversion from pointer to an integer. +// Can not have an implicit conversion between two enums. +// ========================================================================== // + +// CHECK-LABEL: @explicit_voidptr_to_unsigned_int +unsigned int explicit_voidptr_to_unsigned_int(void *src) { + return (unsigned int)src; +} + +// CHECK-LABEL: @explicit_voidptr_to_signed_int +signed int explicit_voidptr_to_signed_int(void *src) { + return (signed int)src; +} + +// Implicit conversions from floating-point. +// ========================================================================== // + +// CHECK-LABEL: @float_to_unsigned_int +unsigned int float_to_unsigned_int(float src) { + return src; +} + +// CHECK-LABEL: @float_to_signed_int +signed int float_to_signed_int(float src) { + return src; +} + +// CHECK-LABEL: @double_to_unsigned_int +unsigned int double_to_unsigned_int(double src) { + return src; +} + +// CHECK-LABEL: @double_to_signed_int +signed int double_to_signed_int(double src) { + return src; +} + +// Sugar. +// ========================================================================== // + +typedef unsigned int uint32_t; + +// CHECK-LABEL: @uint32_to_unsigned_int +unsigned int uint32_to_unsigned_int(uint32_t src) { + return src; +} + +// CHECK-LABEL: @unsigned_int_to_uint32 +uint32_t unsigned_int_to_uint32(unsigned int src) { + return src; +} + +// CHECK-LABEL: @uint32_to_uint32 +uint32_t uint32_to_uint32(uint32_t src) { + return src; +} diff --git a/clang/test/CodeGen/catch-implicit-integer-sign-changes.c b/clang/test/CodeGen/catch-implicit-integer-sign-changes.c new file mode 100644 index 00000000000..e1719048f1a --- /dev/null +++ b/clang/test/CodeGen/catch-implicit-integer-sign-changes.c @@ -0,0 +1,273 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s --check-prefix=CHECK +// RUN: %clang_cc1 -fsanitize=implicit-integer-sign-change -fno-sanitize-recover=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 +// RUN: %clang_cc1 -fsanitize=implicit-integer-sign-change -fsanitize-recover=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 +// RUN: %clang_cc1 -fsanitize=implicit-integer-sign-change -fsanitize-trap=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 + +// CHECK-SANITIZE-ANYRECOVER: @[[UNSIGNED_INT:.*]] = {{.*}} c"'unsigned int'\00" } +// CHECK-SANITIZE-ANYRECOVER-NEXT: @[[SIGNED_INT:.*]] = {{.*}} c"'int'\00" } +// CHECK-SANITIZE-ANYRECOVER-NEXT: @[[LINE_100:.*]] = {{.*}}, i32 100, i32 10 }, {{.*}}* @[[UNSIGNED_INT]], {{.*}}* @[[SIGNED_INT]], i8 3 } +// CHECK-SANITIZE-ANYRECOVER-NEXT: @[[LINE_200:.*]] = {{.*}}, i32 200, i32 10 }, {{.*}}* @[[SIGNED_INT]], {{.*}}* @[[UNSIGNED_INT]], i8 3 } +// CHECK-SANITIZE-ANYRECOVER-NEXT: @[[UNSIGNED_CHAR:.*]] = {{.*}} c"'unsigned char'\00" } +// CHECK-SANITIZE-ANYRECOVER-NEXT: @[[LINE_300:.*]] = {{.*}}, i32 300, i32 10 }, {{.*}}* @[[SIGNED_INT]], {{.*}}* @[[UNSIGNED_CHAR]], i8 3 } +// CHECK-SANITIZE-ANYRECOVER-NEXT: @[[SIGNED_CHAR:.*]] = {{.*}} c"'signed char'\00" } +// CHECK-SANITIZE-ANYRECOVER-NEXT: @[[LINE_400:.*]] = {{.*}}, i32 400, i32 10 }, {{.*}}* @[[SIGNED_CHAR]], {{.*}}* @[[UNSIGNED_CHAR]], i8 3 } +// CHECK-SANITIZE-ANYRECOVER-NEXT: @[[LINE_500:.*]] = {{.*}}, i32 500, i32 10 }, {{.*}}* @[[UNSIGNED_CHAR]], {{.*}}* @[[SIGNED_CHAR]], i8 3 } +// CHECK-SANITIZE-ANYRECOVER-NEXT: @[[LINE_600:.*]] = {{.*}}, i32 600, i32 10 }, {{.*}}* @[[SIGNED_CHAR]], {{.*}}* @[[UNSIGNED_INT]], i8 3 } +// CHECK-SANITIZE-ANYRECOVER-NEXT: @[[LINE_700:.*]] = {{.*}}, i32 700, i32 10 }, {{.*}}* @[[UNSIGNED_INT]], {{.*}}* @[[SIGNED_CHAR]], i8 3 } +// CHECK-SANITIZE-ANYRECOVER-NEXT: @[[LINE_800:.*]] = {{.*}}, i32 800, i32 10 }, {{.*}}* @[[SIGNED_INT]], {{.*}}* @[[SIGNED_CHAR]], i8 3 } +// CHECK-SANITIZE-ANYRECOVER: @[[UINT32:.*]] = {{.*}} c"'uint32_t' (aka 'unsigned int')\00" } +// CHECK-SANITIZE-ANYRECOVER: @[[INT32:.*]] = {{.*}} c"'int32_t' (aka 'int')\00" } +// CHECK-SANITIZE-ANYRECOVER: @[[LINE_900:.*]] = {{.*}}, i32 900, i32 10 }, {{.*}}* @[[UINT32]], {{.*}}* @[[INT32]], i8 3 } + +// ========================================================================== // +// The expected true-positives. +// These are implicit, potentially sign-altering, conversions. +// ========================================================================== // + +// These 3 result (after optimizations) in simple 'icmp sge i32 %src, 0'. + +// CHECK-LABEL: @unsigned_int_to_signed_int +// CHECK-SAME: (i32 %[[SRC:.*]]) +signed int unsigned_int_to_signed_int(unsigned int src) { + // CHECK: %[[SRC_ADDR:.*]] = alloca i32 + // CHECK-NEXT: store i32 %[[SRC]], i32* %[[SRC_ADDR]] + // CHECK-NEXT: %[[DST:.*]] = load i32, i32* %[[SRC_ADDR]] + // CHECK-SANITIZE-NEXT: %[[DST_NEGATIVITYCHECK:.*]] = icmp slt i32 %[[DST]], 0, !nosanitize + // CHECK-SANITIZE-NEXT: %[[SIGNCHANGECHECK:.*]] = icmp eq i1 false, %[[DST_NEGATIVITYCHECK]], !nosanitize + // CHECK-SANITIZE-NEXT: br i1 %[[SIGNCHANGECHECK]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_CONVERSION:[^,]+]],{{.*}} !nosanitize + // CHECK-SANITIZE: [[HANDLER_IMPLICIT_CONVERSION]]: + // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTSRC:.*]] = zext i32 %[[DST]] to i64, !nosanitize + // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTDST:.*]] = zext i32 %[[DST]] to i64, !nosanitize + // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_100]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize + // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_100]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize + // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize + // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize + // CHECK-SANITIZE: [[CONT]]: + // CHECK-NEXT: ret i32 %[[DST]] + // CHECK-NEXT: } +#line 100 + return src; +} + +// CHECK-LABEL: @signed_int_to_unsigned_int +// CHECK-SAME: (i32 %[[SRC:.*]]) +unsigned int signed_int_to_unsigned_int(signed int src) { + // CHECK: %[[SRC_ADDR:.*]] = alloca i32 + // CHECK-NEXT: store i32 %[[SRC]], i32* %[[SRC_ADDR]] + // CHECK-NEXT: %[[DST:.*]] = load i32, i32* %[[SRC_ADDR]] + // CHECK-SANITIZE-NEXT: %[[SRC_NEGATIVITYCHECK:.*]] = icmp slt i32 %[[DST]], 0, !nosanitize + // CHECK-SANITIZE-NEXT: %[[SIGNCHANGECHECK:.*]] = icmp eq i1 %[[SRC_NEGATIVITYCHECK]], false, !nosanitize + // CHECK-SANITIZE-NEXT: br i1 %[[SIGNCHANGECHECK]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_CONVERSION:[^,]+]],{{.*}} !nosanitize + // CHECK-SANITIZE: [[HANDLER_IMPLICIT_CONVERSION]]: + // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTSRC:.*]] = zext i32 %[[DST]] to i64, !nosanitize + // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTDST:.*]] = zext i32 %[[DST]] to i64, !nosanitize + // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_200]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize + // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_200]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize + // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize + // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize + // CHECK-SANITIZE: [[CONT]]: + // CHECK-NEXT: ret i32 %[[DST]] + // CHECK-NEXT: } +#line 200 + return src; +} + +// CHECK-LABEL: @signed_int_to_unsigned_char +// CHECK-SAME: (i32 %[[SRC:.*]]) +unsigned char signed_int_to_unsigned_char(signed int src) { + // CHECK: %[[SRC_ADDR:.*]] = alloca i32 + // CHECK-NEXT: store i32 %[[SRC]], i32* %[[SRC_ADDR]] + // CHECK-NEXT: %[[DST:.*]] = load i32, i32* %[[SRC_ADDR]] + // CHECK-NEXT: %[[CONV:.*]] = trunc i32 %[[DST]] to i8 + // CHECK-SANITIZE-NEXT: %[[SRC_NEGATIVITYCHECK:.*]] = icmp slt i32 %[[DST]], 0, !nosanitize + // CHECK-SANITIZE-NEXT: %[[SIGNCHANGECHECK:.*]] = icmp eq i1 %[[SRC_NEGATIVITYCHECK]], false, !nosanitize + // CHECK-SANITIZE-NEXT: br i1 %[[SIGNCHANGECHECK]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_CONVERSION:[^,]+]],{{.*}} !nosanitize + // CHECK-SANITIZE: [[HANDLER_IMPLICIT_CONVERSION]]: + // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTSRC:.*]] = zext i32 %[[DST]] to i64, !nosanitize + // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTCONV:.*]] = zext i8 %[[CONV]] to i64, !nosanitize + // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_300]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTCONV]]){{.*}}, !nosanitize + // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_300]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTCONV]]){{.*}}, !nosanitize + // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize + // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize + // CHECK-SANITIZE: [[CONT]]: + // CHECK-NEXT: ret i8 %[[CONV]] + // CHECK-NEXT: } +#line 300 + return src; +} + +// These 3 result (after optimizations) in simple 'icmp sge i8 %src, 0' + +// CHECK-LABEL: @signed_char_to_unsigned_char +// CHECK-SAME: (i8 signext %[[SRC:.*]]) +unsigned char signed_char_to_unsigned_char(signed char src) { + // CHECK: %[[SRC_ADDR:.*]] = alloca i8 + // CHECK-NEXT: store i8 %[[SRC]], i8* %[[SRC_ADDR]] + // CHECK-NEXT: %[[DST:.*]] = load i8, i8* %[[SRC_ADDR]] + // CHECK-SANITIZE-NEXT: %[[SRC_NEGATIVITYCHECK:.*]] = icmp slt i8 %[[DST]], 0, !nosanitize + // CHECK-SANITIZE-NEXT: %[[SIGNCHANGECHECK:.*]] = icmp eq i1 %[[SRC_NEGATIVITYCHECK]], false, !nosanitize + // CHECK-SANITIZE-NEXT: br i1 %[[SIGNCHANGECHECK]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_CONVERSION:[^,]+]],{{.*}} !nosanitize + // CHECK-SANITIZE: [[HANDLER_IMPLICIT_CONVERSION]]: + // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTSRC:.*]] = zext i8 %[[DST]] to i64, !nosanitize + // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTDST:.*]] = zext i8 %[[DST]] to i64, !nosanitize + // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_400]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize + // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_400]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize + // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize + // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize + // CHECK-SANITIZE: [[CONT]]: + // CHECK-NEXT: ret i8 %[[DST]] + // CHECK-NEXT: } +#line 400 + return src; +} + +// CHECK-LABEL: @unsigned_char_to_signed_char +// CHECK-SAME: (i8 zeroext %[[SRC:.*]]) +signed char unsigned_char_to_signed_char(unsigned char src) { + // CHECK: %[[SRC_ADDR:.*]] = alloca i8 + // CHECK-NEXT: store i8 %[[SRC]], i8* %[[SRC_ADDR]] + // CHECK-NEXT: %[[DST:.*]] = load i8, i8* %[[SRC_ADDR]] + // CHECK-SANITIZE-NEXT: %[[DST_NEGATIVITYCHECK:.*]] = icmp slt i8 %[[DST]], 0, !nosanitize + // CHECK-SANITIZE-NEXT: %[[SIGNCHANGECHECK:.*]] = icmp eq i1 false, %[[DST_NEGATIVITYCHECK]], !nosanitize + // CHECK-SANITIZE-NEXT: br i1 %[[SIGNCHANGECHECK]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_CONVERSION:[^,]+]],{{.*}} !nosanitize + // CHECK-SANITIZE: [[HANDLER_IMPLICIT_CONVERSION]]: + // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTSRC:.*]] = zext i8 %[[DST]] to i64, !nosanitize + // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTDST:.*]] = zext i8 %[[DST]] to i64, !nosanitize + // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_500]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize + // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_500]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize + // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize + // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize + // CHECK-SANITIZE: [[CONT]]: + // CHECK-NEXT: ret i8 %[[DST]] + // CHECK-NEXT: } +#line 500 + return src; +} + +// CHECK-LABEL: @signed_char_to_unsigned_int +// CHECK-SAME: (i8 signext %[[SRC:.*]]) +unsigned int signed_char_to_unsigned_int(signed char src) { + // CHECK: %[[SRC_ADDR:.*]] = alloca i8 + // CHECK-NEXT: store i8 %[[SRC]], i8* %[[SRC_ADDR]] + // CHECK-NEXT: %[[DST:.*]] = load i8, i8* %[[SRC_ADDR]] + // CHECK-NEXT: %[[CONV:.*]] = sext i8 %[[DST]] to i32 + // CHECK-SANITIZE-NEXT: %[[SRC_NEGATIVITYCHECK:.*]] = icmp slt i8 %[[DST]], 0, !nosanitize + // CHECK-SANITIZE-NEXT: %[[SIGNCHANGECHECK:.*]] = icmp eq i1 %[[SRC_NEGATIVITYCHECK]], false, !nosanitize + // CHECK-SANITIZE-NEXT: br i1 %[[SIGNCHANGECHECK]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_CONVERSION:[^,]+]],{{.*}} !nosanitize + // CHECK-SANITIZE: [[HANDLER_IMPLICIT_CONVERSION]]: + // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTSRC:.*]] = zext i8 %[[DST]] to i64, !nosanitize + // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTCONV:.*]] = zext i32 %[[CONV]] to i64, !nosanitize + // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_600]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTCONV]]){{.*}}, !nosanitize + // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_600]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTCONV]]){{.*}}, !nosanitize + // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize + // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize + // CHECK-SANITIZE: [[CONT]]: + // CHECK-NEXT: ret i32 %[[CONV]] + // CHECK-NEXT: } +#line 600 + return src; +} + +// This one result (after optimizations) in 'icmp sge i8 (trunc i32 %src), 0' + +// CHECK-LABEL: @unsigned_int_to_signed_char +// CHECK-SAME: (i32 %[[SRC:.*]]) +signed char unsigned_int_to_signed_char(unsigned int src) { + // CHECK: %[[SRC_ADDR:.*]] = alloca i32 + // CHECK-NEXT: store i32 %[[SRC]], i32* %[[SRC_ADDR]] + // CHECK-NEXT: %[[DST:.*]] = load i32, i32* %[[SRC_ADDR]] + // CHECK-NEXT: %[[CONV:.*]] = trunc i32 %[[DST]] to i8 + // CHECK-SANITIZE-NEXT: %[[DST_NEGATIVITYCHECK:.*]] = icmp slt i8 %[[CONV]], 0, !nosanitize + // CHECK-SANITIZE-NEXT: %[[SIGNCHANGECHECK:.*]] = icmp eq i1 false, %[[DST_NEGATIVITYCHECK]], !nosanitize + // CHECK-SANITIZE-NEXT: br i1 %[[SIGNCHANGECHECK]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_CONVERSION:[^,]+]],{{.*}} !nosanitize + // CHECK-SANITIZE: [[HANDLER_IMPLICIT_CONVERSION]]: + // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTSRC:.*]] = zext i32 %[[DST]] to i64, !nosanitize + // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTCONV:.*]] = zext i8 %[[CONV]] to i64, !nosanitize + // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_700]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTCONV]]){{.*}}, !nosanitize + // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_700]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTCONV]]){{.*}}, !nosanitize + // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize + // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize + // CHECK-SANITIZE: [[CONT]]: + // CHECK-NEXT: ret i8 %[[CONV]] + // CHECK-NEXT: } +#line 700 + return src; +} + +// The worst one: 'xor i1 (icmp sge i8 (trunc i32 %x), 0), (icmp sge i32 %x, 0)' + +// CHECK-LABEL: @signed_int_to_signed_char +// CHECK-SAME: (i32 %[[SRC:.*]]) +signed char signed_int_to_signed_char(signed int x) { + // CHECK: %[[SRC_ADDR:.*]] = alloca i32 + // CHECK-NEXT: store i32 %[[SRC]], i32* %[[SRC_ADDR]] + // CHECK-NEXT: %[[DST:.*]] = load i32, i32* %[[SRC_ADDR]] + // CHECK-NEXT: %[[CONV:.*]] = trunc i32 %[[DST]] to i8 + // CHECK-SANITIZE-NEXT: %[[SRC_NEGATIVITYCHECK:.*]] = icmp slt i32 %[[DST]], 0, !nosanitize + // CHECK-SANITIZE-NEXT: %[[DST_NEGATIVITYCHECK:.*]] = icmp slt i8 %[[CONV]], 0, !nosanitize + // CHECK-SANITIZE-NEXT: %[[SIGNCHANGECHECK:.*]] = icmp eq i1 %[[SRC_NEGATIVITYCHECK]], %[[DST_NEGATIVITYCHECK]], !nosanitize + // CHECK-SANITIZE-NEXT: br i1 %[[SIGNCHANGECHECK]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_CONVERSION:[^,]+]],{{.*}} !nosanitize + // CHECK-SANITIZE: [[HANDLER_IMPLICIT_CONVERSION]]: + // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTSRC:.*]] = zext i32 %[[DST]] to i64, !nosanitize + // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTCONV:.*]] = zext i8 %[[CONV]] to i64, !nosanitize + // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_800]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTCONV]]){{.*}}, !nosanitize + // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_800]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTCONV]]){{.*}}, !nosanitize + // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize + // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize + // CHECK-SANITIZE: [[CONT]]: + // CHECK-NEXT: ret i8 %[[CONV]] + // CHECK-NEXT: } +#line 800 + return x; +} + +// ========================================================================== // +// Check canonical type stuff +// ========================================================================== // + +typedef unsigned int uint32_t; +typedef signed int int32_t; + +// CHECK-LABEL: @uint32_t_to_int32_t +// CHECK-SAME: (i32 %[[SRC:.*]]) +int32_t uint32_t_to_int32_t(uint32_t src) { + // CHECK: %[[SRC_ADDR:.*]] = alloca i32 + // CHECK-NEXT: store i32 %[[SRC]], i32* %[[SRC_ADDR]] + // CHECK-NEXT: %[[DST:.*]] = load i32, i32* %[[SRC_ADDR]] + // CHECK-SANITIZE-NEXT: %[[DST_NEGATIVITYCHECK:.*]] = icmp slt i32 %[[DST]], 0, !nosanitize + // CHECK-SANITIZE-NEXT: %[[SIGNCHANGECHECK:.*]] = icmp eq i1 false, %[[DST_NEGATIVITYCHECK]], !nosanitize + // CHECK-SANITIZE-NEXT: br i1 %[[SIGNCHANGECHECK]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_CONVERSION:[^,]+]],{{.*}} !nosanitize + // CHECK-SANITIZE: [[HANDLER_IMPLICIT_CONVERSION]]: + // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTSRC:.*]] = zext i32 %[[DST]] to i64, !nosanitize + // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTDST:.*]] = zext i32 %[[DST]] to i64, !nosanitize + // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_900]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize + // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_900]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize + // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize + // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize + // CHECK-SANITIZE: [[CONT]]: + // CHECK-NEXT: ret i32 %[[DST]] + // CHECK-NEXT: } +#line 900 + return src; +} + +// ========================================================================== // +// Check that explicit conversion does not interfere with implicit conversion +// ========================================================================== // +// These contain one implicit and one explicit sign-changing conversion. +// We want to make sure that we still diagnose the implicit conversion. + +// Implicit sign-change after explicit sign-change. +// CHECK-LABEL: @explicit_conversion_interference0 +unsigned int explicit_conversion_interference0(unsigned int c) { + // CHECK-SANITIZE: call + return (signed int)c; +} + +// Implicit sign-change before explicit sign-change. +// CHECK-LABEL: @explicit_conversion_interference1 +unsigned int explicit_conversion_interference1(unsigned int c) { + // CHECK-SANITIZE: call + signed int b; + return (unsigned int)(b = c); +} diff --git a/clang/test/CodeGen/catch-implicit-signed-integer-truncation-or-sign-change.c b/clang/test/CodeGen/catch-implicit-signed-integer-truncation-or-sign-change.c new file mode 100644 index 00000000000..45171baebae --- /dev/null +++ b/clang/test/CodeGen/catch-implicit-signed-integer-truncation-or-sign-change.c @@ -0,0 +1,152 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s --check-prefix=CHECK +// 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 +// 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 +// 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 + +// CHECK-SANITIZE-ANYRECOVER: @[[UNSIGNED_INT:.*]] = {{.*}} c"'unsigned int'\00" } +// CHECK-SANITIZE-ANYRECOVER-NEXT: @[[SIGNED_CHAR:.*]] = {{.*}} c"'signed char'\00" } +// CHECK-SANITIZE-ANYRECOVER-NEXT: @[[LINE_100_SIGNED_TRUNCATION_OR_SIGN_CHANGE:.*]] = {{.*}}, i32 100, i32 10 }, {{.*}}* @[[UNSIGNED_INT]], {{.*}}* @[[SIGNED_CHAR]], i8 4 } +// CHECK-SANITIZE-ANYRECOVER-NEXT: @[[LINE_200_SIGN_CHANGE:.*]] = {{.*}}, i32 200, i32 10 }, {{.*}}* @[[UNSIGNED_INT]], {{.*}}* @[[SIGNED_CHAR]], i8 3 } +// CHECK-SANITIZE-ANYRECOVER-NEXT: @[[LINE_300_SIGN_CHANGE:.*]] = {{.*}}, i32 300, i32 10 }, {{.*}}* @[[UNSIGNED_INT]], {{.*}}* @[[SIGNED_CHAR]], i8 3 } +// CHECK-SANITIZE-ANYRECOVER-NEXT: @[[LINE_400_SIGNED_TRUNCATION:.*]] = {{.*}}, i32 400, i32 10 }, {{.*}}* @[[UNSIGNED_INT]], {{.*}}* @[[SIGNED_CHAR]], i8 2 } + +//============================================================================// +// Both sanitizers are enabled, and not disabled per-function. +//============================================================================// + +// CHECK-LABEL: @unsigned_int_to_signed_char +// CHECK-SAME: (i32 %[[SRC:.*]]) +signed char unsigned_int_to_signed_char(unsigned int src) { + // CHECK-NEXT: [[ENTRY:.*]]: + // CHECK-NEXT: %[[SRC_ADDR:.*]] = alloca i32 + // CHECK-NEXT: store i32 %[[SRC]], i32* %[[SRC_ADDR]] + // CHECK-NEXT: %[[DST:.*]] = load i32, i32* %[[SRC_ADDR]] + // CHECK-NEXT: %[[CONV:.*]] = trunc i32 %[[DST]] to i8 + // CHECK-SANITIZE-NEXT: %[[DST_NEGATIVITYCHECK:.*]] = icmp slt i8 %[[CONV]], 0, !nosanitize + // CHECK-SANITIZE-NEXT: %[[SIGNCHANGECHECK:.*]] = icmp eq i1 false, %[[DST_NEGATIVITYCHECK]], !nosanitize + // CHECK-SANITIZE-NEXT: %[[ANYEXT:.*]] = sext i8 %[[CONV]] to i32, !nosanitize + // CHECK-SANITIZE-NEXT: %[[TRUNCHECK:.*]] = icmp eq i32 %[[ANYEXT]], %[[DST]], !nosanitize + // CHECK-SANITIZE-NEXT: %[[BOTHCHECKS:.*]] = and i1 %[[SIGNCHANGECHECK]], %[[TRUNCHECK]], !nosanitize + // CHECK-SANITIZE-NEXT: br i1 %[[BOTHCHECKS]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_CONVERSION:[^,]+]],{{.*}} !nosanitize + // CHECK-SANITIZE: [[HANDLER_IMPLICIT_CONVERSION]]: + // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTSRC:.*]] = zext i32 %[[DST]] to i64, !nosanitize + // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTCONV:.*]] = zext i8 %[[CONV]] to i64, !nosanitize + // 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 + // 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 + // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize + // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize + // CHECK-SANITIZE: [[CONT]]: + // CHECK-NEXT: ret i8 %[[CONV]] + // CHECK-NEXT: } +#line 100 + return src; +} + +//============================================================================// +// Truncation sanitizer is disabled per-function. +//============================================================================// + +// CHECK-LABEL: @unsigned_int_to_signed_char__no_truncation_sanitizer +// CHECK-SAME: (i32 %[[SRC:.*]]) +__attribute__((no_sanitize("implicit-integer-truncation"))) signed char +unsigned_int_to_signed_char__no_truncation_sanitizer(unsigned int src) { + // CHECK-NEXT: [[ENTRY:.*]]: + // CHECK-NEXT: %[[SRC_ADDR:.*]] = alloca i32 + // CHECK-NEXT: store i32 %[[SRC]], i32* %[[SRC_ADDR]] + // CHECK-NEXT: %[[DST:.*]] = load i32, i32* %[[SRC_ADDR]] + // CHECK-NEXT: %[[CONV:.*]] = trunc i32 %[[DST]] to i8 + // CHECK-SANITIZE-NEXT: %[[DST_NEGATIVITYCHECK:.*]] = icmp slt i8 %[[CONV]], 0, !nosanitize + // CHECK-SANITIZE-NEXT: %[[SIGNCHANGECHECK:.*]] = icmp eq i1 false, %[[DST_NEGATIVITYCHECK]], !nosanitize + // CHECK-SANITIZE-NEXT: br i1 %[[SIGNCHANGECHECK]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_CONVERSION:[^,]+]],{{.*}} !nosanitize + // CHECK-SANITIZE: [[HANDLER_IMPLICIT_CONVERSION]]: + // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTSRC:.*]] = zext i32 %[[DST]] to i64, !nosanitize + // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTCONV:.*]] = zext i8 %[[CONV]] to i64, !nosanitize + // 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 + // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_200_SIGN_CHANGE]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTCONV]]){{.*}}, !nosanitize + // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize + // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize + // CHECK-SANITIZE: [[CONT]]: + // CHECK-NEXT: ret i8 %[[CONV]] + // CHECK-NEXT: } +#line 200 + return src; +} + +//============================================================================// +// Signed truncation sanitizer is disabled per-function. +//============================================================================// + +// CHECK-LABEL: @unsigned_int_to_signed_char__no_signed_truncation_sanitizer +// CHECK-SAME: (i32 %[[SRC:.*]]) +__attribute__((no_sanitize("implicit-signed-integer-truncation"))) signed char +unsigned_int_to_signed_char__no_signed_truncation_sanitizer(unsigned int src) { + // CHECK-NEXT: [[ENTRY:.*]]: + // CHECK-NEXT: %[[SRC_ADDR:.*]] = alloca i32 + // CHECK-NEXT: store i32 %[[SRC]], i32* %[[SRC_ADDR]] + // CHECK-NEXT: %[[DST:.*]] = load i32, i32* %[[SRC_ADDR]] + // CHECK-NEXT: %[[CONV:.*]] = trunc i32 %[[DST]] to i8 + // CHECK-SANITIZE-NEXT: %[[DST_NEGATIVITYCHECK:.*]] = icmp slt i8 %[[CONV]], 0, !nosanitize + // CHECK-SANITIZE-NEXT: %[[SIGNCHANGECHECK:.*]] = icmp eq i1 false, %[[DST_NEGATIVITYCHECK]], !nosanitize + // CHECK-SANITIZE-NEXT: br i1 %[[SIGNCHANGECHECK]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_CONVERSION:[^,]+]],{{.*}} !nosanitize + // CHECK-SANITIZE: [[HANDLER_IMPLICIT_CONVERSION]]: + // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTSRC:.*]] = zext i32 %[[DST]] to i64, !nosanitize + // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTCONV:.*]] = zext i8 %[[CONV]] to i64, !nosanitize + // 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 + // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_300_SIGN_CHANGE]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTCONV]]){{.*}}, !nosanitize + // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize + // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize + // CHECK-SANITIZE: [[CONT]]: + // CHECK-NEXT: ret i8 %[[CONV]] + // CHECK-NEXT: } +#line 300 + return src; +} + +//============================================================================// +// Sign change sanitizer is disabled per-function +//============================================================================// + +// CHECK-LABEL: @unsigned_int_to_signed_char__no_sign_change_sanitizer +// CHECK-SAME: (i32 %[[SRC:.*]]) +__attribute__((no_sanitize("implicit-integer-sign-change"))) signed char +unsigned_int_to_signed_char__no_sign_change_sanitizer(unsigned int src) { + // CHECK-NEXT: [[ENTRY:.*]]: + // CHECK-NEXT: %[[SRC_ADDR:.*]] = alloca i32 + // CHECK-NEXT: store i32 %[[SRC]], i32* %[[SRC_ADDR]] + // CHECK-NEXT: %[[DST:.*]] = load i32, i32* %[[SRC_ADDR]] + // CHECK-NEXT: %[[CONV:.*]] = trunc i32 %[[DST]] to i8 + // CHECK-SANITIZE-NEXT: %[[ANYEXT:.*]] = sext i8 %[[CONV]] to i32, !nosanitize + // CHECK-SANITIZE-NEXT: %[[TRUNCHECK:.*]] = icmp eq i32 %[[ANYEXT]], %[[DST]], !nosanitize + // CHECK-SANITIZE-NEXT: br i1 %[[TRUNCHECK]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_CONVERSION:[^,]+]],{{.*}} !nosanitize + // CHECK-SANITIZE: [[HANDLER_IMPLICIT_CONVERSION]]: + // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTSRC:.*]] = zext i32 %[[DST]] to i64, !nosanitize + // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTCONV:.*]] = zext i8 %[[CONV]] to i64, !nosanitize + // 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 + // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_400_SIGNED_TRUNCATION]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTCONV]]){{.*}}, !nosanitize + // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize + // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize + // CHECK-SANITIZE: [[CONT]]: + // CHECK-NEXT: ret i8 %[[CONV]] + // CHECK-NEXT: } +#line 400 + return src; +} + +//============================================================================// +// Both sanitizers are disabled per-function. +//============================================================================// + +// CHECK-LABEL: @unsigned_int_to_signed_char__no_sanitizers +// CHECK-SAME: (i32 %[[SRC:.*]]) +__attribute__((no_sanitize("implicit-integer-truncation"), + no_sanitize("implicit-integer-sign-change"))) signed char +unsigned_int_to_signed_char__no_sanitizers(unsigned int src) { + // CHECK-NEXT: [[ENTRY:.*]]: + // CHECK-NEXT: %[[SRC_ADDR:.*]] = alloca i32 + // CHECK-NEXT: store i32 %[[SRC]], i32* %[[SRC_ADDR]] + // CHECK-NEXT: %[[DST:.*]] = load i32, i32* %[[SRC_ADDR]] + // CHECK-NEXT: %[[CONV:.*]] = trunc i32 %[[DST]] to i8 + // CHECK-NEXT: ret i8 %[[CONV]] + // CHECK-NEXT: } + return src; +} diff --git a/clang/test/CodeGenCXX/catch-implicit-integer-sign-changes-true-negatives.cpp b/clang/test/CodeGenCXX/catch-implicit-integer-sign-changes-true-negatives.cpp new file mode 100644 index 00000000000..95349387b3b --- /dev/null +++ b/clang/test/CodeGenCXX/catch-implicit-integer-sign-changes-true-negatives.cpp @@ -0,0 +1,149 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s --check-prefix=CHECK +// RUN: %clang_cc1 -fsanitize=implicit-integer-sign-change -fno-sanitize-recover=implicit-integer-sign-change -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s --check-prefixes=CHECK,CHECK-SANITIZE,CHECK-SANITIZE-ANYRECOVER,CHECK-SANITIZE-NORECOVER +// RUN: %clang_cc1 -fsanitize=implicit-integer-sign-change -fsanitize-recover=implicit-integer-sign-change -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s --check-prefixes=CHECK,CHECK-SANITIZE,CHECK-SANITIZE-ANYRECOVER,CHECK-SANITIZE-RECOVER +// RUN: %clang_cc1 -fsanitize=implicit-integer-sign-change -fsanitize-trap=implicit-integer-sign-change -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s --check-prefixes=CHECK,CHECK-SANITIZE,CHECK-SANITIZE-TRAP + +extern "C" { // Disable name mangling. + +// ========================================================================== // +// The expected true-negatives. +// ========================================================================== // + +// Sanitization is explicitly disabled. +// ========================================================================== // + +// CHECK-LABEL: @blacklist_0 +__attribute__((no_sanitize("undefined"))) unsigned int blacklist_0(signed int src) { + // We are not in "undefined" group, so that doesn't work. + // CHECK-SANITIZE: call + // CHECK: } + return src; +} + +// CHECK-LABEL: @blacklist_1 +__attribute__((no_sanitize("integer"))) unsigned int blacklist_1(signed int src) { + // CHECK-SANITIZE-NOT: call + // CHECK: } + return src; +} + +// CHECK-LABEL: @blacklist_2 +__attribute__((no_sanitize("implicit-conversion"))) unsigned int blacklist_2(signed int src) { + // CHECK-SANITIZE-NOT: call + // CHECK: } + return src; +} + +// CHECK-LABEL: @blacklist_3 +__attribute__((no_sanitize("implicit-integer-sign-change"))) unsigned int blacklist_3(signed int src) { + // CHECK-SANITIZE-NOT: call + // CHECK: } + return src; +} + +// Explicit sign-changing conversions. +// ========================================================================== // + +// CHECK-LABEL: @explicit_signed_int_to_unsigned_int +unsigned int explicit_signed_int_to_unsigned_int(signed int src) { + // CHECK-SANITIZE-NOT: call + // CHECK: } + return (unsigned int)src; +} + +// CHECK-LABEL: @explicit_unsigned_int_to_signed_int +signed int explicit_unsigned_int_to_signed_int(unsigned int src) { + // CHECK-SANITIZE-NOT: call + // CHECK: } + return (signed int)src; +} + +// Explicit NOP conversions. +// ========================================================================== // + +// CHECK-LABEL: @explicit_unsigned_int_to_unsigned_int +unsigned int explicit_unsigned_int_to_unsigned_int(unsigned int src) { + // CHECK-SANITIZE-NOT: call + // CHECK: } + return (unsigned int)src; +} + +// CHECK-LABEL: @explicit_signed_int_to_signed_int +signed int explicit_signed_int_to_signed_int(signed int src) { + // CHECK-SANITIZE-NOT: call + // CHECK: } + return (signed int)src; +} + +// Explicit functional sign-changing casts. +// ========================================================================== // + +using UnsignedInt = unsigned int; +using SignedInt = signed int; + +// CHECK-LABEL: explicit_functional_unsigned_int_to_signed_int +signed int explicit_functional_unsigned_int_to_signed_int(unsigned int src) { + // CHECK-SANITIZE-NOT: call + // CHECK: } + return SignedInt(src); +} + +// CHECK-LABEL: @explicit_functional_signed_int_to_unsigned_int +unsigned int explicit_functional_signed_int_to_unsigned_int(signed int src) { + // CHECK-SANITIZE-NOT: call + // CHECK: } + return UnsignedInt(src); +} + +// Explicit functional NOP casts. +// ========================================================================== // + +// CHECK-LABEL: @explicit_functional_unsigned_int_to_unsigned_int +unsigned int explicit_functional_unsigned_int_to_unsigned_int(unsigned int src) { + // CHECK-SANITIZE-NOT: call + // CHECK: } + return UnsignedInt(src); +} + +// CHECK-LABEL: @explicit_functional_signed_int_to_signed_int +signed int explicit_functional_signed_int_to_signed_int(signed int src) { + // CHECK-SANITIZE-NOT: call + // CHECK: } + return SignedInt(src); +} + +// Explicit C++-style sign-changing casts. +// ========================================================================== // + +// CHECK-LABEL: @explicit_cppstyle_unsigned_int_to_signed_int +signed int explicit_cppstyle_unsigned_int_to_signed_int(unsigned int src) { + // CHECK-SANITIZE-NOT: call + // CHECK: } + return static_cast<signed int>(src); +} + +// CHECK-LABEL: @explicit_cppstyle_signed_int_to_unsigned_int +unsigned int explicit_cppstyle_signed_int_to_unsigned_int(signed int src) { + // CHECK-SANITIZE-NOT: call + // CHECK: } + return static_cast<unsigned int>(src); +} + +// Explicit C++-style casts NOP casts. +// ========================================================================== // + +// CHECK-LABEL: @explicit_cppstyle_unsigned_int_to_unsigned_int +unsigned int explicit_cppstyle_unsigned_int_to_unsigned_int(unsigned int src) { + // CHECK-SANITIZE-NOT: call + // CHECK: } + return static_cast<unsigned int>(src); +} + +// CHECK-LABEL: @explicit_cppstyle_signed_int_to_signed_int +signed int explicit_cppstyle_signed_int_to_signed_int(signed int src) { + // CHECK-SANITIZE-NOT: call + // CHECK: } + return static_cast<signed int>(src); +} + +} // extern "C" diff --git a/clang/test/Driver/fsanitize.c b/clang/test/Driver/fsanitize.c index 51d910c3041..ac4a7d27b38 100644 --- a/clang/test/Driver/fsanitize.c +++ b/clang/test/Driver/fsanitize.c @@ -31,22 +31,37 @@ // CHECK-COVERAGE-WIN64: "--dependent-lib={{[^"]*}}ubsan_standalone-x86_64.lib" // RUN: %clang -target x86_64-linux-gnu -fsanitize=integer %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-INTEGER -implicit-check-not="-fsanitize-address-use-after-scope" -// CHECK-INTEGER: "-fsanitize={{((signed-integer-overflow|unsigned-integer-overflow|integer-divide-by-zero|shift-base|shift-exponent|implicit-unsigned-integer-truncation|implicit-signed-integer-truncation),?){7}"}} +// CHECK-INTEGER: "-fsanitize={{((signed-integer-overflow|unsigned-integer-overflow|integer-divide-by-zero|shift-base|shift-exponent|implicit-unsigned-integer-truncation|implicit-signed-integer-truncation|implicit-integer-sign-change),?){8}"}} // RUN: %clang -target x86_64-linux-gnu -fsanitize=implicit-conversion %s -### 2>&1 | FileCheck %s --check-prefixes=CHECK-implicit-conversion,CHECK-implicit-conversion-RECOVER // RUN: %clang -target x86_64-linux-gnu -fsanitize=implicit-conversion -fsanitize-recover=implicit-conversion %s -### 2>&1 | FileCheck %s --check-prefixes=CHECK-implicit-conversion,CHECK-implicit-conversion-RECOVER // RUN: %clang -target x86_64-linux-gnu -fsanitize=implicit-conversion -fno-sanitize-recover=implicit-conversion %s -### 2>&1 | FileCheck %s --check-prefixes=CHECK-implicit-conversion,CHECK-implicit-conversion-NORECOVER // RUN: %clang -target x86_64-linux-gnu -fsanitize=implicit-conversion -fsanitize-trap=implicit-conversion %s -### 2>&1 | FileCheck %s --check-prefixes=CHECK-implicit-conversion,CHECK-implicit-conversion-TRAP -// CHECK-implicit-conversion: "-fsanitize={{((implicit-unsigned-integer-truncation|implicit-signed-integer-truncation),?){2}"}} -// CHECK-implicit-conversion-RECOVER: "-fsanitize-recover={{((implicit-unsigned-integer-truncation|implicit-signed-integer-truncation),?){2}"}} -// CHECK-implicit-conversion-RECOVER-NOT: "-fno-sanitize-recover={{((implicit-unsigned-integer-truncation|implicit-signed-integer-truncation),?){2}"}} -// CHECK-implicit-conversion-RECOVER-NOT: "-fsanitize-trap={{((implicit-unsigned-integer-truncation|implicit-signed-integer-truncation),?){2}"}} -// CHECK-implicit-conversion-NORECOVER-NOT: "-fno-sanitize-recover={{((implicit-unsigned-integer-truncation|implicit-signed-integer-truncation),?){2}"}} // ??? -// CHECK-implicit-conversion-NORECOVER-NOT: "-fsanitize-recover={{((implicit-unsigned-integer-truncation|implicit-signed-integer-truncation),?){2}"}} -// CHECK-implicit-conversion-NORECOVER-NOT: "-fsanitize-trap={{((implicit-unsigned-integer-truncation|implicit-signed-integer-truncation),?){2}"}} -// CHECK-implicit-conversion-TRAP: "-fsanitize-trap={{((implicit-unsigned-integer-truncation|implicit-signed-integer-truncation),?){2}"}} -// CHECK-implicit-conversion-TRAP-NOT: "-fsanitize-recover={{((implicit-unsigned-integer-truncation|implicit-signed-integer-truncation),?){2}"}} -// CHECK-implicit-conversion-TRAP-NOT: "-fno-sanitize-recover={{((implicit-unsigned-integer-truncation|implicit-signed-integer-truncation),?){2}"}} +// CHECK-implicit-conversion: "-fsanitize={{((implicit-unsigned-integer-truncation|implicit-signed-integer-truncation|implicit-integer-sign-change),?){3}"}} +// CHECK-implicit-conversion-RECOVER: "-fsanitize-recover={{((implicit-unsigned-integer-truncation|implicit-signed-integer-truncation|implicit-integer-sign-change),?){3}"}} +// CHECK-implicit-conversion-RECOVER-NOT: "-fno-sanitize-recover={{((implicit-unsigned-integer-truncation|implicit-signed-integer-truncation|implicit-integer-sign-change),?){3}"}} +// CHECK-implicit-conversion-RECOVER-NOT: "-fsanitize-trap={{((implicit-unsigned-integer-truncation|implicit-signed-integer-truncation|implicit-integer-sign-change),?){3}"}} +// CHECK-implicit-conversion-NORECOVER-NOT: "-fno-sanitize-recover={{((implicit-unsigned-integer-truncation|implicit-signed-integer-truncation|implicit-integer-sign-change),?){3}"}} // ??? +// CHECK-implicit-conversion-NORECOVER-NOT: "-fsanitize-recover={{((implicit-unsigned-integer-truncation|implicit-signed-integer-truncation|implicit-integer-sign-change),?){3}"}} +// CHECK-implicit-conversion-NORECOVER-NOT: "-fsanitize-trap={{((implicit-unsigned-integer-truncation|implicit-signed-integer-truncation|implicit-integer-sign-change),?){3}"}} +// CHECK-implicit-conversion-TRAP: "-fsanitize-trap={{((implicit-unsigned-integer-truncation|implicit-signed-integer-truncation|implicit-integer-sign-change),?){3}"}} +// CHECK-implicit-conversion-TRAP-NOT: "-fsanitize-recover={{((implicit-unsigned-integer-truncation|implicit-signed-integer-truncation|implicit-integer-sign-change),?){3}"}} +// CHECK-implicit-conversion-TRAP-NOT: "-fno-sanitize-recover={{((implicit-unsigned-integer-truncation|implicit-signed-integer-truncation|implicit-integer-sign-change),?){3}"}} + +// RUN: %clang -target x86_64-linux-gnu -fsanitize=implicit-integer-arithmetic-value-change %s -### 2>&1 | FileCheck %s --check-prefixes=CHECK-implicit-integer-arithmetic-value-change,CHECK-implicit-integer-arithmetic-value-change-RECOVER +// RUN: %clang -target x86_64-linux-gnu -fsanitize=implicit-integer-arithmetic-value-change -fsanitize-recover=implicit-integer-arithmetic-value-change %s -### 2>&1 | FileCheck %s --check-prefixes=CHECK-implicit-integer-arithmetic-value-change,CHECK-implicit-integer-arithmetic-value-change-RECOVER +// RUN: %clang -target x86_64-linux-gnu -fsanitize=implicit-integer-arithmetic-value-change -fno-sanitize-recover=implicit-integer-arithmetic-value-change %s -### 2>&1 | FileCheck %s --check-prefixes=CHECK-implicit-integer-arithmetic-value-change,CHECK-implicit-integer-arithmetic-value-change-NORECOVER +// RUN: %clang -target x86_64-linux-gnu -fsanitize=implicit-integer-arithmetic-value-change -fsanitize-trap=implicit-integer-arithmetic-value-change %s -### 2>&1 | FileCheck %s --check-prefixes=CHECK-implicit-integer-arithmetic-value-change,CHECK-implicit-integer-arithmetic-value-change-TRAP +// CHECK-implicit-integer-arithmetic-value-change: "-fsanitize={{((implicit-signed-integer-truncation|implicit-integer-sign-change),?){2}"}} +// CHECK-implicit-integer-arithmetic-value-change-RECOVER: "-fsanitize-recover={{((implicit-signed-integer-truncation|implicit-integer-sign-change),?){2}"}} +// CHECK-implicit-integer-arithmetic-value-change-RECOVER-NOT: "-fno-sanitize-recover={{((implicit-signed-integer-truncation|implicit-integer-sign-change),?){2}"}} +// CHECK-implicit-integer-arithmetic-value-change-RECOVER-NOT: "-fsanitize-trap={{((implicit-signed-integer-truncation|implicit-integer-sign-change),?){2}"}} +// CHECK-implicit-integer-arithmetic-value-change-NORECOVER-NOT: "-fno-sanitize-recover={{((implicit-signed-integer-truncation|implicit-integer-sign-change),?){2}"}} // ??? +// CHECK-implicit-integer-arithmetic-value-change-NORECOVER-NOT: "-fsanitize-recover={{((implicit-signed-integer-truncation|implicit-integer-sign-change),?){2}"}} +// CHECK-implicit-integer-arithmetic-value-change-NORECOVER-NOT: "-fsanitize-trap={{((implicit-signed-integer-truncation|implicit-integer-sign-change),?){2}"}} +// CHECK-implicit-integer-arithmetic-value-change-TRAP: "-fsanitize-trap={{((implicit-signed-integer-truncation|implicit-integer-sign-change),?){2}"}} +// CHECK-implicit-integer-arithmetic-value-change-TRAP-NOT: "-fsanitize-recover={{((implicit-signed-integer-truncation|implicit-integer-sign-change),?){2}"}} +// CHECK-implicit-integer-arithmetic-value-change-TRAP-NOT: "-fno-sanitize-recover={{((implicit-signed-integer-truncation|implicit-integer-sign-change),?){2}"}} // RUN: %clang -target x86_64-linux-gnu -fsanitize=implicit-integer-truncation %s -### 2>&1 | FileCheck %s --check-prefixes=CHECK-implicit-integer-truncation,CHECK-implicit-integer-truncation-RECOVER // RUN: %clang -target x86_64-linux-gnu -fsanitize=implicit-integer-truncation -fsanitize-recover=implicit-integer-truncation %s -### 2>&1 | FileCheck %s --check-prefixes=CHECK-implicit-integer-truncation,CHECK-implicit-integer-truncation-RECOVER |

