Index: docs/UndefinedBehaviorSanitizer.rst =================================================================== --- docs/UndefinedBehaviorSanitizer.rst +++ docs/UndefinedBehaviorSanitizer.rst @@ -89,10 +89,15 @@ - ``-fsanitize=function``: Indirect call of a function through a function pointer of the wrong type (Darwin/Linux, C++ and x86/x86_64 only). - - ``-fsanitize=implicit-integer-truncation``: Implicit conversion from + - ``-fsanitize=implicit-unsigned-integer-truncation``, + ``-fsanitize=implicit-signed-integer-truncation``: Implicit conversion from integer of larger bit width to smaller bit width, if that results in data loss. That is, if the demoted value, after casting back to the original width, is not equal to the original value before the downcast. + The ``-fsanitize=implicit-unsigned-integer-truncation`` handles conversions + between two ``unsigned`` types, while + ``-fsanitize=implicit-signed-integer-truncation`` handles the rest of the + conversions - when either one, or both of the types are signed. Issues caught by this sanitizer are not undefined behavior, but are often unintentional. - ``-fsanitize=integer-divide-by-zero``: Integer division by zero. @@ -160,6 +165,10 @@ behavior (e.g. unsigned integer overflow). Enables ``signed-integer-overflow``, ``unsigned-integer-overflow``, ``shift``, ``integer-divide-by-zero``, and ``implicit-integer-truncation``. + - ``fsanitize=implicit-integer-truncation``: Checks for implicit integral + conversions that result in data loss. + Enables ``implicit-unsigned-integer-truncation`` and + ``implicit-signed-integer-truncation``. - ``-fsanitize=implicit-conversion``: Checks for suspicious behaviours of implicit conversions. Currently, only ``-fsanitize=implicit-integer-truncation`` is implemented. Index: include/clang/Basic/Sanitizers.def =================================================================== --- include/clang/Basic/Sanitizers.def +++ include/clang/Basic/Sanitizers.def @@ -132,7 +132,13 @@ SANITIZER_GROUP("undefined-trap", UndefinedTrap, Undefined) // ImplicitConversionSanitizer -SANITIZER("implicit-integer-truncation", ImplicitIntegerTruncation) +SANITIZER("implicit-unsigned-integer-truncation", + ImplicitUnsignedIntegerTruncation) +SANITIZER("implicit-signed-integer-truncation", ImplicitSignedIntegerTruncation) +SANITIZER_GROUP("implicit-integer-truncation", ImplicitIntegerTruncation, + ImplicitUnsignedIntegerTruncation | + ImplicitSignedIntegerTruncation) + SANITIZER_GROUP("implicit-conversion", ImplicitConversion, ImplicitIntegerTruncation) Index: lib/CodeGen/CGExprScalar.cpp =================================================================== --- lib/CodeGen/CGExprScalar.cpp +++ lib/CodeGen/CGExprScalar.cpp @@ -302,7 +302,9 @@ /// Known implicit conversion check kinds. /// Keep in sync with the enum of the same name in ubsan_handlers.h enum ImplicitConversionCheckKind : unsigned char { - ICCK_IntegerTruncation = 0, + ICCK_IntegerTruncation = 0, // Legacy, no longer used. + ICCK_UnsignedIntegerTruncation = 1, + ICCK_SignedIntegerTruncation = 2, }; /// Emit a check that an [implicit] truncation of an integer does not @@ -944,7 +946,7 @@ void ScalarExprEmitter::EmitIntegerTruncationCheck(Value *Src, QualType SrcType, Value *Dst, QualType DstType, SourceLocation Loc) { - if (!CGF.SanOpts.has(SanitizerKind::ImplicitIntegerTruncation)) + if (!CGF.SanOpts.hasOneOf(SanitizerKind::ImplicitIntegerTruncation)) return; llvm::Type *SrcTy = Src->getType(); @@ -966,13 +968,31 @@ assert(!DstType->isBooleanType() && "we should not get here with booleans."); + bool SrcSigned = SrcType->isSignedIntegerOrEnumerationType(); + bool DstSigned = DstType->isSignedIntegerOrEnumerationType(); + + // If both (src and dst) types are unsigned, then it's an unsigned truncation. + // Else, it is a signed truncation. + ImplicitConversionCheckKind Kind; + SanitizerMask Mask; + if (!SrcSigned && !DstSigned) { + Kind = ICCK_UnsignedIntegerTruncation; + Mask = SanitizerKind::ImplicitUnsignedIntegerTruncation; + } else { + Kind = ICCK_SignedIntegerTruncation; + Mask = SanitizerKind::ImplicitSignedIntegerTruncation; + } + + // Do we care about this type of truncation? + if (!CGF.SanOpts.has(Mask)) + return; + CodeGenFunction::SanitizerScope SanScope(&CGF); llvm::Value *Check = nullptr; // 1. Extend the truncated value back to the same width as the Src. - bool InputSigned = DstType->isSignedIntegerOrEnumerationType(); - Check = Builder.CreateIntCast(Dst, SrcTy, InputSigned, "anyext"); + Check = Builder.CreateIntCast(Dst, SrcTy, DstSigned, "anyext"); // 2. Equality-compare with the original source value Check = Builder.CreateICmpEQ(Check, Src, "truncheck"); // If the comparison result is 'i1 false', then the truncation was lossy. @@ -980,8 +1000,8 @@ llvm::Constant *StaticArgs[] = { CGF.EmitCheckSourceLocation(Loc), CGF.EmitCheckTypeDescriptor(SrcType), CGF.EmitCheckTypeDescriptor(DstType), - llvm::ConstantInt::get(Builder.getInt8Ty(), ICCK_IntegerTruncation)}; - CGF.EmitCheck(std::make_pair(Check, SanitizerKind::ImplicitIntegerTruncation), + llvm::ConstantInt::get(Builder.getInt8Ty(), Kind)}; + CGF.EmitCheck(std::make_pair(Check, Mask), SanitizerHandler::ImplicitConversion, StaticArgs, {Src, Dst}); } @@ -1876,7 +1896,7 @@ case CK_IntegralCast: { ScalarConversionOpts Opts; - if (CGF.SanOpts.has(SanitizerKind::ImplicitIntegerTruncation)) { + if (CGF.SanOpts.hasOneOf(SanitizerKind::ImplicitIntegerTruncation)) { if (auto *ICE = dyn_cast(CE)) Opts.EmitImplicitIntegerTruncationChecks = !ICE->isPartOfExplicitCast(); } Index: test/CodeGen/catch-implicit-integer-conversions-basics.c =================================================================== --- test/CodeGen/catch-implicit-integer-conversions-basics.c +++ test/CodeGen/catch-implicit-integer-conversions-basics.c @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsanitize=implicit-integer-truncation -fsanitize-recover=implicit-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 -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 // Test plan: // * Two types - int and char @@ -9,123 +9,107 @@ // 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_TRUNCATION:.*]] = {{.*}}, i32 500, i32 10 }, {{.*}}, {{.*}}, i8 0 } -// CHECK-DAG: @[[LINE_1100_TRUNCATION:.*]] = {{.*}}, i32 1100, i32 10 }, {{.*}}, {{.*}}, i8 0 } -// CHECK-DAG: @[[LINE_1500_TRUNCATION:.*]] = {{.*}}, i32 1500, i32 10 }, {{.*}}, {{.*}}, i8 0 } -// CHECK-DAG: @[[LINE_1600_TRUNCATION:.*]] = {{.*}}, i32 1600, i32 10 }, {{.*}}, {{.*}}, i8 0 } +// CHECK-DAG: @[[LINE_500_UNSIGNED_TRUNCATION:.*]] = {{.*}}, i32 500, i32 10 }, {{.*}}, {{.*}}, i8 1 } +// 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_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) { - // CHECK: } #line 100 return x; } // CHECK-LABEL: @convert_unsigned_char_to_unsigned_char unsigned char convert_unsigned_char_to_unsigned_char(unsigned char x) { - // CHECK: } #line 200 return x; } // CHECK-LABEL: @convert_signed_int_to_signed_int signed int convert_signed_int_to_signed_int(signed int x) { - // CHECK: } #line 300 return x; } // CHECK-LABEL: @convert_signed_char_to_signed_char signed char convert_signed_char_to_signed_char(signed char x) { - // CHECK: } #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_TRUNCATION]] to i8*) - // CHECK: } + // 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) { - // CHECK: } #line 600 return x; } // CHECK-LABEL: @convert_unsigned_char_to_signed_int signed int convert_unsigned_char_to_signed_int(unsigned char x) { - // CHECK: } #line 700 return x; } // CHECK-LABEL: @convert_signed_char_to_signed_int signed int convert_signed_char_to_signed_int(signed char x) { - // CHECK: } #line 800 return x; } // CHECK-LABEL: @convert_unsigned_int_to_signed_int signed int convert_unsigned_int_to_signed_int(unsigned int x) { - // CHECK: } #line 900 return x; } // CHECK-LABEL: @convert_signed_int_to_unsigned_int unsigned int convert_signed_int_to_unsigned_int(signed int x) { - // CHECK: } #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_TRUNCATION]] to i8*) - // CHECK: } + // 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: } #line 1200 return x; } // CHECK-LABEL: @convert_unsigned_char_to_signed_char signed char convert_unsigned_char_to_signed_char(unsigned char x) { - // CHECK: } #line 1300 return x; } // CHECK-LABEL: @convert_signed_char_to_unsigned_int unsigned int convert_signed_char_to_unsigned_int(signed char x) { - // CHECK: } #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_TRUNCATION]] to i8*) - // CHECK: } + // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1500_SIGNED_TRUNCATION]] 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_TRUNCATION]] to i8*) - // CHECK: } + // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1600_SIGNED_TRUNCATION]] to i8*) #line 1600 return x; } Index: test/CodeGen/catch-implicit-integer-truncations-basics-negatives.c =================================================================== --- /dev/null +++ test/CodeGen/catch-implicit-integer-truncations-basics-negatives.c @@ -0,0 +1,86 @@ +// 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-DAG: @[[LINE_100_UNSIGNED_TRUNCATION:.*]] = {{.*}}, i32 100, i32 10 }, {{.*}}, {{.*}}, i8 1 } +// CHECK-DAG: @[[LINE_200_UNSIGNED_TRUNCATION:.*]] = {{.*}}, i32 200, i32 10 }, {{.*}}, {{.*}}, i8 1 } +// CHECK-DAG: @[[LINE_300_SIGNED_TRUNCATION:.*]] = {{.*}}, i32 300, i32 10 }, {{.*}}, {{.*}}, i8 2 } +// CHECK-DAG: @[[LINE_400_SIGNED_TRUNCATION:.*]] = {{.*}}, i32 400, i32 10 }, {{.*}}, {{.*}}, i8 2 } + +//----------------------------------------------------------------------------// +// Unsigned case. +//----------------------------------------------------------------------------// + +// CHECK-LABEL: @blacklist_0_convert_unsigned_int_to_unsigned_char +__attribute__((no_sanitize("undefined"))) unsigned char blacklist_0_convert_unsigned_int_to_unsigned_char(unsigned int x) { + // We are not in "undefined" group, so that doesn't work. + // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_100_UNSIGNED_TRUNCATION]] to i8*) +#line 100 + return x; +} + +// CHECK-LABEL: @blacklist_1_convert_unsigned_int_to_unsigned_char +__attribute__((no_sanitize("integer"))) unsigned char blacklist_1_convert_unsigned_int_to_unsigned_char(unsigned int x) { + return x; +} + +// CHECK-LABEL: @blacklist_2_convert_unsigned_int_to_unsigned_char +__attribute__((no_sanitize("implicit-conversion"))) unsigned char blacklist_2_convert_unsigned_int_to_unsigned_char(unsigned int x) { + return x; +} + +// CHECK-LABEL: @blacklist_3_convert_unsigned_int_to_unsigned_char +__attribute__((no_sanitize("implicit-integer-truncation"))) unsigned char blacklist_3_convert_unsigned_int_to_unsigned_char(unsigned int x) { + return x; +} + +// CHECK-LABEL: @blacklist_4_convert_unsigned_int_to_unsigned_char +__attribute__((no_sanitize("implicit-unsigned-integer-truncation"))) unsigned char blacklist_4_convert_unsigned_int_to_unsigned_char(unsigned int x) { + return x; +} + +// CHECK-LABEL: @blacklist_5_convert_unsigned_int_to_unsigned_char +__attribute__((no_sanitize("implicit-signed-integer-truncation"))) unsigned char blacklist_5_convert_unsigned_int_to_unsigned_char(unsigned int x) { + // This is an unsigned truncation, not signed-one. + // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_200_UNSIGNED_TRUNCATION]] to i8*) +#line 200 + return x; +} + +//----------------------------------------------------------------------------// +// Signed case. +//----------------------------------------------------------------------------// + +// CHECK-LABEL: @blacklist_0_convert_signed_int_to_signed_char +__attribute__((no_sanitize("undefined"))) signed char blacklist_0_convert_signed_int_to_signed_char(signed int x) { + // We are not in "undefined" group, so that doesn't work. + // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_300_SIGNED_TRUNCATION]] to i8*) +#line 300 + return x; +} + +// CHECK-LABEL: @blacklist_1_convert_signed_int_to_signed_char +__attribute__((no_sanitize("integer"))) signed char blacklist_1_convert_signed_int_to_signed_char(signed int x) { + return x; +} + +// CHECK-LABEL: @blacklist_2_convert_signed_int_to_signed_char +__attribute__((no_sanitize("implicit-conversion"))) signed char blacklist_2_convert_signed_int_to_signed_char(signed int x) { + return x; +} + +// CHECK-LABEL: @blacklist_3_convert_signed_int_to_signed_char +__attribute__((no_sanitize("implicit-integer-truncation"))) signed char blacklist_3_convert_signed_int_to_signed_char(signed int x) { + return x; +} + +// CHECK-LABEL: @blacklist_4_convert_signed_int_to_signed_char +__attribute__((no_sanitize("implicit-signed-integer-truncation"))) signed char blacklist_4_convert_signed_int_to_signed_char(signed int x) { + return x; +} + +// CHECK-LABEL: @blacklist_5_convert_signed_int_to_signed_char +__attribute__((no_sanitize("implicit-unsigned-integer-truncation"))) signed char blacklist_5_convert_signed_int_to_signed_char(signed int x) { + // This is an signed truncation, not unsigned-one. + // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_400_SIGNED_TRUNCATION]] to i8*) +#line 400 + return x; +} Index: test/CodeGen/catch-implicit-integer-truncations-basics.c =================================================================== --- test/CodeGen/catch-implicit-integer-truncations-basics.c +++ test/CodeGen/catch-implicit-integer-truncations-basics.c @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsanitize=implicit-integer-truncation -fsanitize-recover=implicit-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 -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 // Test plan: // * Two types - int and char @@ -9,123 +9,107 @@ // 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_TRUNCATION:.*]] = {{.*}}, i32 500, i32 10 }, {{.*}}, {{.*}}, i8 0 } -// CHECK-DAG: @[[LINE_1100_TRUNCATION:.*]] = {{.*}}, i32 1100, i32 10 }, {{.*}}, {{.*}}, i8 0 } -// CHECK-DAG: @[[LINE_1500_TRUNCATION:.*]] = {{.*}}, i32 1500, i32 10 }, {{.*}}, {{.*}}, i8 0 } -// CHECK-DAG: @[[LINE_1600_TRUNCATION:.*]] = {{.*}}, i32 1600, i32 10 }, {{.*}}, {{.*}}, i8 0 } +// CHECK-DAG: @[[LINE_500_UNSIGNED_TRUNCATION:.*]] = {{.*}}, i32 500, i32 10 }, {{.*}}, {{.*}}, i8 1 } +// 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_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) { - // CHECK: } #line 100 return x; } // CHECK-LABEL: @convert_unsigned_char_to_unsigned_char unsigned char convert_unsigned_char_to_unsigned_char(unsigned char x) { - // CHECK: } #line 200 return x; } // CHECK-LABEL: @convert_signed_int_to_signed_int signed int convert_signed_int_to_signed_int(signed int x) { - // CHECK: } #line 300 return x; } // CHECK-LABEL: @convert_signed_char_to_signed_char signed char convert_signed_char_to_signed_char(signed char x) { - // CHECK: } #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_TRUNCATION]] to i8*) - // CHECK: } + // 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) { - // CHECK: } #line 600 return x; } // CHECK-LABEL: @convert_unsigned_char_to_signed_int signed int convert_unsigned_char_to_signed_int(unsigned char x) { - // CHECK: } #line 700 return x; } // CHECK-LABEL: @convert_signed_char_to_signed_int signed int convert_signed_char_to_signed_int(signed char x) { - // CHECK: } #line 800 return x; } // CHECK-LABEL: @convert_unsigned_int_to_signed_int signed int convert_unsigned_int_to_signed_int(unsigned int x) { - // CHECK: } #line 900 return x; } // CHECK-LABEL: @convert_signed_int_to_unsigned_int unsigned int convert_signed_int_to_unsigned_int(signed int x) { - // CHECK: } #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_TRUNCATION]] to i8*) - // CHECK: } + // 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: } #line 1200 return x; } // CHECK-LABEL: @convert_unsigned_char_to_signed_char signed char convert_unsigned_char_to_signed_char(unsigned char x) { - // CHECK: } #line 1300 return x; } // CHECK-LABEL: @convert_signed_char_to_unsigned_int unsigned int convert_signed_char_to_unsigned_int(signed char x) { - // CHECK: } #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_TRUNCATION]] to i8*) - // CHECK: } + // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1500_SIGNED_TRUNCATION]] 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_TRUNCATION]] to i8*) - // CHECK: } + // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1600_SIGNED_TRUNCATION]] to i8*) #line 1600 return x; } Index: test/CodeGen/catch-implicit-integer-truncations.c =================================================================== --- test/CodeGen/catch-implicit-integer-truncations.c +++ test/CodeGen/catch-implicit-integer-truncations.c @@ -1,21 +1,21 @@ // RUN: %clang_cc1 -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s --check-prefix=CHECK -// RUN: %clang_cc1 -fsanitize=implicit-integer-truncation -fno-sanitize-recover=implicit-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 -// RUN: %clang_cc1 -fsanitize=implicit-integer-truncation -fsanitize-recover=implicit-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 -// RUN: %clang_cc1 -fsanitize=implicit-integer-truncation -fsanitize-trap=implicit-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 +// 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 +// 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 +// 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 // CHECK-SANITIZE-ANYRECOVER: @[[UNSIGNED_INT:.*]] = {{.*}} c"'unsigned int'\00" } // CHECK-SANITIZE-ANYRECOVER: @[[UNSIGNED_CHAR:.*]] = {{.*}} c"'unsigned char'\00" } -// CHECK-SANITIZE-ANYRECOVER: @[[LINE_100:.*]] = {{.*}}, i32 100, i32 10 }, {{.*}}* @[[UNSIGNED_INT]], {{.*}}* @[[UNSIGNED_CHAR]], i8 0 } +// CHECK-SANITIZE-ANYRECOVER: @[[LINE_100_UNSIGNED_TRUNCATION:.*]] = {{.*}}, i32 100, i32 10 }, {{.*}}* @[[UNSIGNED_INT]], {{.*}}* @[[UNSIGNED_CHAR]], i8 1 } // CHECK-SANITIZE-ANYRECOVER: @[[SIGNED_INT:.*]] = {{.*}} c"'int'\00" } -// CHECK-SANITIZE-ANYRECOVER: @[[LINE_200:.*]] = {{.*}}, i32 200, i32 10 }, {{.*}}* @[[SIGNED_INT]], {{.*}}* @[[UNSIGNED_CHAR]], i8 0 } +// CHECK-SANITIZE-ANYRECOVER: @[[LINE_200_SIGNED_TRUNCATION:.*]] = {{.*}}, i32 200, i32 10 }, {{.*}}* @[[SIGNED_INT]], {{.*}}* @[[UNSIGNED_CHAR]], i8 2 } // CHECK-SANITIZE-ANYRECOVER: @[[SIGNED_CHAR:.*]] = {{.*}} c"'signed char'\00" } -// CHECK-SANITIZE-ANYRECOVER: @[[LINE_300:.*]] = {{.*}}, i32 300, i32 10 }, {{.*}}* @[[UNSIGNED_INT]], {{.*}}* @[[SIGNED_CHAR]], i8 0 } -// CHECK-SANITIZE-ANYRECOVER: @[[LINE_400:.*]] = {{.*}}, i32 400, i32 10 }, {{.*}}* @[[SIGNED_INT]], {{.*}}* @[[SIGNED_CHAR]], i8 0 } +// CHECK-SANITIZE-ANYRECOVER: @[[LINE_300_SIGNED_TRUNCATION:.*]] = {{.*}}, i32 300, i32 10 }, {{.*}}* @[[UNSIGNED_INT]], {{.*}}* @[[SIGNED_CHAR]], i8 2 } +// CHECK-SANITIZE-ANYRECOVER: @[[LINE_400_SIGNED_TRUNCATION:.*]] = {{.*}}, i32 400, i32 10 }, {{.*}}* @[[SIGNED_INT]], {{.*}}* @[[SIGNED_CHAR]], i8 2 } // CHECK-SANITIZE-ANYRECOVER: @[[UINT32:.*]] = {{.*}} c"'uint32_t' (aka 'unsigned int')\00" } // CHECK-SANITIZE-ANYRECOVER: @[[UINT8:.*]] = {{.*}} c"'uint8_t' (aka 'unsigned char')\00" } -// CHECK-SANITIZE-ANYRECOVER: @[[LINE_500:.*]] = {{.*}}, i32 500, i32 10 }, {{.*}}* @[[UINT32]], {{.*}}* @[[UINT8]], i8 0 } +// CHECK-SANITIZE-ANYRECOVER: @[[LINE_500_UNSIGNED_TRUNCATION:.*]] = {{.*}}, i32 500, i32 10 }, {{.*}}* @[[UINT32]], {{.*}}* @[[UINT8]], i8 1 } // ========================================================================== // // The expected true-positives. These are implicit conversions, and they truncate. @@ -30,8 +30,8 @@ // CHECK-SANITIZE: [[HANDLER_IMPLICIT_CONVERSION]]: // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTSRC:.*]] = zext i32 %[[SRC]] 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_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-NORECOVER-NEXT: call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_100_UNSIGNED_TRUNCATION]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize + // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_100_UNSIGNED_TRUNCATION]] 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]]: @@ -50,8 +50,8 @@ // CHECK-SANITIZE: [[HANDLER_IMPLICIT_CONVERSION]]: // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTSRC:.*]] = zext i32 %[[SRC]] 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_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-NORECOVER-NEXT: call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_200_SIGNED_TRUNCATION]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize + // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_200_SIGNED_TRUNCATION]] 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]]: @@ -70,8 +70,8 @@ // CHECK-SANITIZE: [[HANDLER_IMPLICIT_CONVERSION]]: // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTSRC:.*]] = zext i32 %[[SRC]] 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_300]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize - // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_300]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize + // 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 + // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_300_SIGNED_TRUNCATION]] 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]]: @@ -90,8 +90,8 @@ // CHECK-SANITIZE: [[HANDLER_IMPLICIT_CONVERSION]]: // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTSRC:.*]] = zext i32 %[[SRC]] 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-NORECOVER-NEXT: call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_400_SIGNED_TRUNCATION]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize + // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_400_SIGNED_TRUNCATION]] 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]]: @@ -117,8 +117,8 @@ // CHECK-SANITIZE: [[HANDLER_IMPLICIT_CONVERSION]]: // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTSRC:.*]] = zext i32 %[[SRC]] 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-NORECOVER-NEXT: call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_500_UNSIGNED_TRUNCATION]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize + // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_500_UNSIGNED_TRUNCATION]] 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]]: @@ -139,7 +139,6 @@ unsigned char explicit_conversion_interference0(unsigned int c) { // CHECK-SANITIZE: %[[ANYEXT:.*]] = zext i8 %[[DST:.*]] to i16, !nosanitize // CHECK-SANITIZE: call - // CHECK: } return (unsigned short)c; } @@ -148,7 +147,6 @@ unsigned char explicit_conversion_interference1(unsigned int c) { // CHECK-SANITIZE: %[[ANYEXT:.*]] = zext i16 %[[DST:.*]] to i32, !nosanitize // CHECK-SANITIZE: call - // CHECK: } unsigned short b; return (unsigned char)(b = c); } @@ -164,25 +162,21 @@ __attribute__((no_sanitize("undefined"))) unsigned char blacklist_0(unsigned 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 char blacklist_1(unsigned int src) { - // CHECK: } return src; } // CHECK-LABEL: @blacklist_2 __attribute__((no_sanitize("implicit-conversion"))) unsigned char blacklist_2(unsigned int src) { - // CHECK: } return src; } // CHECK-LABEL: @blacklist_3 __attribute__((no_sanitize("implicit-integer-truncation"))) unsigned char blacklist_3(unsigned int src) { - // CHECK: } return src; } @@ -191,25 +185,21 @@ // CHECK-LABEL: @explicit_unsigned_int_to_unsigned_char unsigned char explicit_unsigned_int_to_unsigned_char(unsigned int src) { - // CHECK: } return (unsigned char)src; } // CHECK-LABEL: @explicit_signed_int_to_unsigned_char unsigned char explicit_signed_int_to_unsigned_char(signed int src) { - // CHECK: } return (unsigned char)src; } // CHECK-LABEL: @explicit_unsigned_int_to_signed_char signed char explicit_unsigned_int_to_signed_char(unsigned int src) { - // CHECK: } return (signed char)src; } // CHECK-LABEL: @explicit_signed_int_to_signed_char signed char explicit_signed_int_to_signed_char(signed int src) { - // CHECK: } return (signed char)src; } @@ -218,25 +208,21 @@ // CHECK-LABEL: @explicit_unsigned_int_to_unsigned_int unsigned int explicit_unsigned_int_to_unsigned_int(unsigned int src) { - // 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: } return (signed int)src; } // CHECK-LABEL: @explicit_unsigned_char_to_signed_char unsigned char explicit_unsigned_char_to_signed_char(unsigned char src) { - // CHECK: } return (unsigned char)src; } // CHECK-LABEL: @explicit_signed_char_to_signed_char signed char explicit_signed_char_to_signed_char(signed char src) { - // CHECK: } return (signed char)src; } @@ -245,25 +231,21 @@ // CHECK-LABEL: @unsigned_char_to_unsigned_int unsigned int unsigned_char_to_unsigned_int(unsigned char src) { - // CHECK: } return src; } // CHECK-LABEL: @signed_char_to_unsigned_int unsigned int signed_char_to_unsigned_int(signed char src) { - // CHECK: } return src; } // CHECK-LABEL: @unsigned_char_to_signed_int signed int unsigned_char_to_signed_int(unsigned char src) { - // CHECK: } return src; } // CHECK-LABEL: @signed_char_to_signed_int signed int signed_char_to_signed_int(signed char src) { - // CHECK: } return src; } @@ -272,25 +254,21 @@ // CHECK-LABEL: @explicit_unsigned_char_to_unsigned_int unsigned int explicit_unsigned_char_to_unsigned_int(unsigned char src) { - // CHECK: } return (unsigned int)src; } // CHECK-LABEL: @explicit_signed_char_to_unsigned_int unsigned int explicit_signed_char_to_unsigned_int(signed char src) { - // CHECK: } return (unsigned int)src; } // CHECK-LABEL: @explicit_unsigned_char_to_signed_int signed int explicit_unsigned_char_to_signed_int(unsigned char src) { - // CHECK: } return (signed int)src; } // CHECK-LABEL: @explicit_signed_char_to_signed_int signed int explicit_signed_char_to_signed_int(signed char src) { - // CHECK: } return (signed int)src; } @@ -299,25 +277,21 @@ // CHECK-LABEL: @unsigned_int_to_bool _Bool unsigned_int_to_bool(unsigned int src) { - // CHECK: } return src; } // CHECK-LABEL: @signed_int_to_bool _Bool signed_int_to_bool(signed int src) { - // CHECK: } return src; } // CHECK-LABEL: @explicit_unsigned_int_to_bool _Bool explicit_unsigned_int_to_bool(unsigned int src) { - // CHECK: } return (_Bool)src; } // CHECK-LABEL: @explicit_signed_int_to_bool _Bool explicit_signed_int_to_bool(signed int src) { - // CHECK: } return (_Bool)src; } @@ -328,13 +302,11 @@ // CHECK-LABEL: @explicit_voidptr_to_unsigned_char unsigned char explicit_voidptr_to_unsigned_char(void *src) { - // CHECK: } return (unsigned char)src; } // CHECK-LABEL: @explicit_voidptr_to_signed_char signed char explicit_voidptr_to_signed_char(void *src) { - // CHECK: } return (signed char)src; } @@ -343,25 +315,21 @@ // CHECK-LABEL: @float_to_unsigned_int unsigned int float_to_unsigned_int(float src) { - // CHECK: } return src; } // CHECK-LABEL: @float_to_signed_int signed int float_to_signed_int(float src) { - // CHECK: } return src; } // CHECK-LABEL: @double_to_unsigned_int unsigned int double_to_unsigned_int(double src) { - // CHECK: } return src; } // CHECK-LABEL: @double_to_signed_int signed int double_to_signed_int(double src) { - // CHECK: } return src; } @@ -370,6 +338,5 @@ // CHECK-LABEL: @double_to_float float double_to_float(double src) { - // CHECK: } return src; } Index: test/CodeGen/catch-implicit-signed-integer-truncations-basics-negatives.c =================================================================== --- /dev/null +++ test/CodeGen/catch-implicit-signed-integer-truncations-basics-negatives.c @@ -0,0 +1,40 @@ +// RUN: %clang_cc1 -fsanitize=implicit-signed-integer-truncation -fsanitize-recover=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-DAG: @[[LINE_100_SIGNED_TRUNCATION:.*]] = {{.*}}, i32 100, i32 10 }, {{.*}}, {{.*}}, i8 2 } +// CHECK-DAG: @[[LINE_200_SIGNED_TRUNCATION:.*]] = {{.*}}, i32 200, i32 10 }, {{.*}}, {{.*}}, i8 2 } + +// CHECK-LABEL: @blacklist_0_convert_signed_int_to_signed_char +__attribute__((no_sanitize("undefined"))) signed char blacklist_0_convert_signed_int_to_signed_char(signed int x) { + // We are not in "undefined" group, so that doesn't work. + // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_100_SIGNED_TRUNCATION]] to i8*) +#line 100 + return x; +} + +// CHECK-LABEL: @blacklist_1_convert_signed_int_to_signed_char +__attribute__((no_sanitize("integer"))) signed char blacklist_1_convert_signed_int_to_signed_char(signed int x) { + return x; +} + +// CHECK-LABEL: @blacklist_2_convert_signed_int_to_signed_char +__attribute__((no_sanitize("implicit-conversion"))) signed char blacklist_2_convert_signed_int_to_signed_char(signed int x) { + return x; +} + +// CHECK-LABEL: @blacklist_3_convert_signed_int_to_signed_char +__attribute__((no_sanitize("implicit-integer-truncation"))) signed char blacklist_3_convert_signed_int_to_signed_char(signed int x) { + return x; +} + +// CHECK-LABEL: @blacklist_4_convert_signed_int_to_signed_char +__attribute__((no_sanitize("implicit-signed-integer-truncation"))) signed char blacklist_4_convert_signed_int_to_signed_char(signed int x) { + return x; +} + +// CHECK-LABEL: @blacklist_5_convert_signed_int_to_signed_char +__attribute__((no_sanitize("implicit-unsigned-integer-truncation"))) signed char blacklist_5_convert_signed_int_to_signed_char(signed int x) { + // This is an signed truncation, not unsigned-one. + // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_200_SIGNED_TRUNCATION]] to i8*) +#line 200 + return x; +} Index: test/CodeGen/catch-implicit-signed-integer-truncations-basics.c =================================================================== --- /dev/null +++ test/CodeGen/catch-implicit-signed-integer-truncations-basics.c @@ -0,0 +1,113 @@ +// RUN: %clang_cc1 -fsanitize=implicit-signed-integer-truncation -fsanitize-recover=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 + +// 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_1100_SIGNED_TRUNCATION:.*]] = {{.*}}, i32 1100, i32 10 }, {{.*}}, {{.*}}, i8 2 } +// CHECK-DAG: @[[LINE_1500_SIGNED_TRUNCATION:.*]] = {{.*}}, i32 1500, i32 10 }, {{.*}}, {{.*}}, i8 2 } +// 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) { +#line 900 + return x; +} + +// CHECK-LABEL: @convert_signed_int_to_unsigned_int +unsigned int convert_signed_int_to_unsigned_int(signed int x) { +#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) { +#line 1200 + return x; +} + +// CHECK-LABEL: @convert_unsigned_char_to_signed_char +signed char convert_unsigned_char_to_signed_char(unsigned char x) { +#line 1300 + return x; +} + +// CHECK-LABEL: @convert_signed_char_to_unsigned_int +unsigned int convert_signed_char_to_unsigned_int(signed char x) { +#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*) +#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; +} Index: test/CodeGen/catch-implicit-unsigned-integer-truncations-basics-negatives.c =================================================================== --- /dev/null +++ test/CodeGen/catch-implicit-unsigned-integer-truncations-basics-negatives.c @@ -0,0 +1,40 @@ +// RUN: %clang_cc1 -fsanitize=implicit-unsigned-integer-truncation -fsanitize-recover=implicit-unsigned-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-DAG: @[[LINE_100_UNSIGNED_TRUNCATION:.*]] = {{.*}}, i32 100, i32 10 }, {{.*}}, {{.*}}, i8 1 } +// CHECK-DAG: @[[LINE_200_UNSIGNED_TRUNCATION:.*]] = {{.*}}, i32 200, i32 10 }, {{.*}}, {{.*}}, i8 1 } + +// CHECK-LABEL: @blacklist_0_convert_unsigned_int_to_unsigned_char +__attribute__((no_sanitize("undefined"))) unsigned char blacklist_0_convert_unsigned_int_to_unsigned_char(unsigned int x) { + // We are not in "undefined" group, so that doesn't work. + // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_100_UNSIGNED_TRUNCATION]] to i8*) +#line 100 + return x; +} + +// CHECK-LABEL: @blacklist_1_convert_unsigned_int_to_unsigned_char +__attribute__((no_sanitize("integer"))) unsigned char blacklist_1_convert_unsigned_int_to_unsigned_char(unsigned int x) { + return x; +} + +// CHECK-LABEL: @blacklist_2_convert_unsigned_int_to_unsigned_char +__attribute__((no_sanitize("implicit-conversion"))) unsigned char blacklist_2_convert_unsigned_int_to_unsigned_char(unsigned int x) { + return x; +} + +// CHECK-LABEL: @blacklist_3_convert_unsigned_int_to_unsigned_char +__attribute__((no_sanitize("implicit-integer-truncation"))) unsigned char blacklist_3_convert_unsigned_int_to_unsigned_char(unsigned int x) { + return x; +} + +// CHECK-LABEL: @blacklist_4_convert_unsigned_int_to_unsigned_char +__attribute__((no_sanitize("implicit-unsigned-integer-truncation"))) unsigned char blacklist_4_convert_unsigned_int_to_unsigned_char(unsigned int x) { + return x; +} + +// CHECK-LABEL: @blacklist_5_convert_unsigned_int_to_unsigned_char +__attribute__((no_sanitize("implicit-signed-integer-truncation"))) unsigned char blacklist_5_convert_unsigned_int_to_unsigned_char(unsigned int x) { + // This is an unsigned truncation, not signed-one. + // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_200_UNSIGNED_TRUNCATION]] to i8*) +#line 200 + return x; +} Index: test/CodeGen/catch-implicit-unsigned-integer-truncations-basics.c =================================================================== --- /dev/null +++ test/CodeGen/catch-implicit-unsigned-integer-truncations-basics.c @@ -0,0 +1,109 @@ +// RUN: %clang_cc1 -fsanitize=implicit-unsigned-integer-truncation -fsanitize-recover=implicit-unsigned-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 + +// 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-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) { +#line 900 + return x; +} + +// CHECK-LABEL: @convert_signed_int_to_unsigned_int +unsigned int convert_signed_int_to_unsigned_int(signed int x) { +#line 1000 + return x; +} + +// CHECK-LABEL: @convert_signed_int_to_unsigned_char +unsigned char convert_signed_int_to_unsigned_char(signed int x) { +#line 1100 + return x; +} + +// CHECK-LABEL: @convert_signed_char_to_unsigned_char +unsigned char convert_signed_char_to_unsigned_char(signed char x) { +#line 1200 + return x; +} + +// CHECK-LABEL: @convert_unsigned_char_to_signed_char +signed char convert_unsigned_char_to_signed_char(unsigned char x) { +#line 1300 + return x; +} + +// CHECK-LABEL: @convert_signed_char_to_unsigned_int +unsigned int convert_signed_char_to_unsigned_int(signed char x) { +#line 1400 + return x; +} + +// CHECK-LABEL: @convert_unsigned_int_to_signed_char +signed char convert_unsigned_int_to_signed_char(unsigned int x) { +#line 1500 + return x; +} + +// CHECK-LABEL: @convert_signed_int_to_signed_char +signed char convert_signed_int_to_signed_char(signed int x) { +#line 1600 + return x; +} Index: test/CodeGenCXX/catch-implicit-integer-truncations.cpp =================================================================== --- test/CodeGenCXX/catch-implicit-integer-truncations.cpp +++ test/CodeGenCXX/catch-implicit-integer-truncations.cpp @@ -1,7 +1,7 @@ // RUN: %clang_cc1 -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s --check-prefix=CHECK -// RUN: %clang_cc1 -fsanitize=implicit-integer-truncation -fno-sanitize-recover=implicit-integer-truncation -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-truncation -fsanitize-recover=implicit-integer-truncation -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-truncation -fsanitize-trap=implicit-integer-truncation -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s --check-prefixes=CHECK,CHECK-SANITIZE,CHECK-SANITIZE-TRAP +// 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 --check-prefixes=CHECK,CHECK-SANITIZE,CHECK-SANITIZE-ANYRECOVER,CHECK-SANITIZE-NORECOVER +// 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 --check-prefixes=CHECK,CHECK-SANITIZE,CHECK-SANITIZE-ANYRECOVER,CHECK-SANITIZE-RECOVER +// 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 --check-prefixes=CHECK,CHECK-SANITIZE,CHECK-SANITIZE-TRAP extern "C" { // Disable name mangling. Index: test/Driver/fsanitize.c =================================================================== --- test/Driver/fsanitize.c +++ test/Driver/fsanitize.c @@ -29,22 +29,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-integer-truncation),?){6}"}} +// 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}"}} // 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-integer-truncation),?){1}"}} -// CHECK-implicit-conversion-RECOVER: "-fsanitize-recover={{((implicit-integer-truncation),?){1}"}} -// CHECK-implicit-conversion-RECOVER-NOT: "-fno-sanitize-recover={{((implicit-integer-truncation),?){1}"}} -// CHECK-implicit-conversion-RECOVER-NOT: "-fsanitize-trap={{((implicit-integer-truncation),?){1}"}} -// CHECK-implicit-conversion-NORECOVER-NOT: "-fno-sanitize-recover={{((implicit-integer-truncation),?){1}"}} // ??? -// CHECK-implicit-conversion-NORECOVER-NOT: "-fsanitize-recover={{((implicit-integer-truncation),?){1}"}} -// CHECK-implicit-conversion-NORECOVER-NOT: "-fsanitize-trap={{((implicit-integer-truncation),?){1}"}} -// CHECK-implicit-conversion-TRAP: "-fsanitize-trap={{((implicit-integer-truncation),?){1}"}} -// CHECK-implicit-conversion-TRAP-NOT: "-fsanitize-recover={{((implicit-integer-truncation),?){1}"}} -// CHECK-implicit-conversion-TRAP-NOT: "-fno-sanitize-recover={{((implicit-integer-truncation),?){1}"}} +// 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}"}} + +// 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 +// RUN: %clang -target x86_64-linux-gnu -fsanitize=implicit-integer-truncation -fno-sanitize-recover=implicit-integer-truncation %s -### 2>&1 | FileCheck %s --check-prefixes=CHECK-implicit-integer-truncation,CHECK-implicit-integer-truncation-NORECOVER +// RUN: %clang -target x86_64-linux-gnu -fsanitize=implicit-integer-truncation -fsanitize-trap=implicit-integer-truncation %s -### 2>&1 | FileCheck %s --check-prefixes=CHECK-implicit-integer-truncation,CHECK-implicit-integer-truncation-TRAP +// CHECK-implicit-integer-truncation: "-fsanitize={{((implicit-unsigned-integer-truncation|implicit-signed-integer-truncation),?){2}"}} +// CHECK-implicit-integer-truncation-RECOVER: "-fsanitize-recover={{((implicit-unsigned-integer-truncation|implicit-signed-integer-truncation),?){2}"}} +// CHECK-implicit-integer-truncation-RECOVER-NOT: "-fno-sanitize-recover={{((implicit-unsigned-integer-truncation|implicit-signed-integer-truncation),?){2}"}} +// CHECK-implicit-integer-truncation-RECOVER-NOT: "-fsanitize-trap={{((implicit-unsigned-integer-truncation|implicit-signed-integer-truncation),?){2}"}} +// CHECK-implicit-integer-truncation-NORECOVER-NOT: "-fno-sanitize-recover={{((implicit-unsigned-integer-truncation|implicit-signed-integer-truncation),?){2}"}} // ??? +// CHECK-implicit-integer-truncation-NORECOVER-NOT: "-fsanitize-recover={{((implicit-unsigned-integer-truncation|implicit-signed-integer-truncation),?){2}"}} +// CHECK-implicit-integer-truncation-NORECOVER-NOT: "-fsanitize-trap={{((implicit-unsigned-integer-truncation|implicit-signed-integer-truncation),?){2}"}} +// CHECK-implicit-integer-truncation-TRAP: "-fsanitize-trap={{((implicit-unsigned-integer-truncation|implicit-signed-integer-truncation),?){2}"}} +// CHECK-implicit-integer-truncation-TRAP-NOT: "-fsanitize-recover={{((implicit-unsigned-integer-truncation|implicit-signed-integer-truncation),?){2}"}} +// CHECK-implicit-integer-truncation-TRAP-NOT: "-fno-sanitize-recover={{((implicit-unsigned-integer-truncation|implicit-signed-integer-truncation),?){2}"}} // RUN: %clang -fsanitize=bounds -### -fsyntax-only %s 2>&1 | FileCheck %s --check-prefix=CHECK-BOUNDS // CHECK-BOUNDS: "-fsanitize={{((array-bounds|local-bounds),?){2}"}}