]> granicus.if.org Git - clang/commitdiff
[clang][ubsan] Split Implicit Integer Truncation Sanitizer into unsigned and signed...
authorRoman Lebedev <lebedev.ri@gmail.com>
Thu, 11 Oct 2018 09:09:50 +0000 (09:09 +0000)
committerRoman Lebedev <lebedev.ri@gmail.com>
Thu, 11 Oct 2018 09:09:50 +0000 (09:09 +0000)
Summary:
As per IRC disscussion, it seems we really want to have more fine-grained `-fsanitize=implicit-integer-truncation`:
* A check when both of the types are unsigned.
* Another check for the other cases (either one of the types is signed, or both of the types is signed).

This is clang part.
Compiler-rt part is D50902.

Reviewers: rsmith, vsk, Sanitizers

Reviewed by: rsmith

Differential Revision: https://reviews.llvm.org/D50901

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@344230 91177308-0d34-0410-b5e6-96231b3b80d8

13 files changed:
docs/UndefinedBehaviorSanitizer.rst
include/clang/Basic/Sanitizers.def
lib/CodeGen/CGExprScalar.cpp
test/CodeGen/catch-implicit-integer-conversions-basics.c
test/CodeGen/catch-implicit-integer-truncations-basics-negatives.c
test/CodeGen/catch-implicit-integer-truncations-basics.c
test/CodeGen/catch-implicit-integer-truncations.c
test/CodeGen/catch-implicit-signed-integer-truncations-basics-negatives.c [new file with mode: 0644]
test/CodeGen/catch-implicit-signed-integer-truncations-basics.c [new file with mode: 0644]
test/CodeGen/catch-implicit-unsigned-integer-truncations-basics-negatives.c [new file with mode: 0644]
test/CodeGen/catch-implicit-unsigned-integer-truncations-basics.c [new file with mode: 0644]
test/CodeGenCXX/catch-implicit-integer-truncations.cpp
test/Driver/fsanitize.c

index 86d0193a23c25d144f6ef92e2b5b1aad229210ea..c971f634d7af1329a9a6e2e87146cc2a4fb87a93 100644 (file)
@@ -89,11 +89,16 @@ Available checks are:
   -  ``-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.
-     Issues caught by this sanitizer are not undefined behavior,
+     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 these sanitizers are not undefined behavior,
      but are often unintentional.
   -  ``-fsanitize=integer-divide-by-zero``: Integer division by zero.
   -  ``-fsanitize=nonnull-attribute``: Passing null pointer as a function
@@ -160,6 +165,10 @@ You can also use the following check groups:
      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 c3fc1750b7dd5dd0c9a10758b29c875e96b7e6bf..41bfc064d85c11c31bb4a29d9c8db66bae1f147b 100644 (file)
@@ -135,7 +135,13 @@ SANITIZER_GROUP("undefined", Undefined,
 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 4995db28ba3dc2263410deda0c8860f28455b832..0bbd788f028826b9c0553fd00098627a3ffb1f8b 100644 (file)
@@ -302,7 +302,9 @@ public:
   /// 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, was only used by clang 7.
+    ICCK_UnsignedIntegerTruncation = 1,
+    ICCK_SignedIntegerTruncation = 2,
   };
 
   /// Emit a check that an [implicit] truncation of an integer  does not
@@ -944,7 +946,7 @@ void ScalarExprEmitter::EmitFloatConversionCheck(
 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 @@ void ScalarExprEmitter::EmitIntegerTruncationCheck(Value *Src, QualType SrcType,
 
   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 @@ void ScalarExprEmitter::EmitIntegerTruncationCheck(Value *Src, QualType SrcType,
   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 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
 
   case CK_IntegralCast: {
     ScalarConversionOpts Opts;
-    if (CGF.SanOpts.has(SanitizerKind::ImplicitIntegerTruncation)) {
+    if (CGF.SanOpts.hasOneOf(SanitizerKind::ImplicitIntegerTruncation)) {
       if (auto *ICE = dyn_cast<ImplicitCastExpr>(CE))
         Opts.EmitImplicitIntegerTruncationChecks = !ICE->isPartOfExplicitCast();
     }
index 987f54c551d07d3443565faf41e53a713fe0fcd3..1a34246d78bdf8067ed1bcb8eddf0d2005cf91bb 100644 (file)
@@ -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,10 +9,10 @@
 // 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) {
@@ -40,7 +40,7 @@ signed char convert_signed_char_to_signed_char(signed char 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: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_500_UNSIGNED_TRUNCATION]] to i8*)
 #line 500
   return x;
 }
@@ -77,7 +77,7 @@ unsigned int convert_signed_int_to_unsigned_int(signed int 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: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1100_SIGNED_TRUNCATION]] to i8*)
 #line 1100
   return x;
 }
@@ -102,14 +102,14 @@ unsigned int convert_signed_char_to_unsigned_int(signed char 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: 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: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1600_SIGNED_TRUNCATION]] to i8*)
 #line 1600
   return x;
 }
index d5554b98d4a421b3171e9fc162b5c85786ede96c..1b543a3a7ff075f651026456d35126d225568cdb 100644 (file)
@@ -1,7 +1,9 @@
-// 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
 
-// CHECK-DAG: @[[LINE_100_TRUNCATION:.*]] = {{.*}}, i32 100, i32 10 }, {{.*}}, {{.*}}, i8 0 }
-// CHECK-DAG: @[[LINE_300_TRUNCATION:.*]] = {{.*}}, i32 300, i32 10 }, {{.*}}, {{.*}}, i8 0 }
+// 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.
@@ -10,7 +12,7 @@
 // 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_TRUNCATION]] to i8*)
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_100_UNSIGNED_TRUNCATION]] to i8*)
 #line 100
   return x;
 }
@@ -30,6 +32,19 @@ __attribute__((no_sanitize("implicit-integer-truncation"))) unsigned char blackl
   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.
 //----------------------------------------------------------------------------//
@@ -37,7 +52,7 @@ __attribute__((no_sanitize("implicit-integer-truncation"))) unsigned char blackl
 // 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_TRUNCATION]] to i8*)
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_300_SIGNED_TRUNCATION]] to i8*)
 #line 300
   return x;
 }
@@ -56,3 +71,16 @@ __attribute__((no_sanitize("implicit-conversion"))) signed char blacklist_2_conv
 __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 987f54c551d07d3443565faf41e53a713fe0fcd3..1a34246d78bdf8067ed1bcb8eddf0d2005cf91bb 100644 (file)
@@ -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,10 +9,10 @@
 // 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) {
@@ -40,7 +40,7 @@ signed char convert_signed_char_to_signed_char(signed char 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: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_500_UNSIGNED_TRUNCATION]] to i8*)
 #line 500
   return x;
 }
@@ -77,7 +77,7 @@ unsigned int convert_signed_int_to_unsigned_int(signed int 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: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1100_SIGNED_TRUNCATION]] to i8*)
 #line 1100
   return x;
 }
@@ -102,14 +102,14 @@ unsigned int convert_signed_char_to_unsigned_int(signed char 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: 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: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1600_SIGNED_TRUNCATION]] to i8*)
 #line 1600
   return x;
 }
index ea5b476c22002bc1ba6e4c0d971ed9e0aa27064f..bcc9273439b9d262485d508e2ca6cf0cd18375c3 100644 (file)
@@ -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_TRUNCATION:.*]] = {{.*}}, 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_TRUNCATION:.*]] = {{.*}}, 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_TRUNCATION:.*]] = {{.*}}, i32 300, i32 10 }, {{.*}}* @[[UNSIGNED_INT]], {{.*}}* @[[SIGNED_CHAR]], i8 0 }
-// CHECK-SANITIZE-ANYRECOVER: @[[LINE_400_TRUNCATION:.*]] = {{.*}}, 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_TRUNCATION:.*]] = {{.*}}, 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 @@ unsigned char unsigned_int_to_unsigned_char(unsigned int src) {
   // 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_TRUNCATION]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
-  // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_100_TRUNCATION]] 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 @@ unsigned char signed_int_to_unsigned_char(signed int src) {
   // 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_TRUNCATION]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
-  // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_200_TRUNCATION]] 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 @@ signed char unsigned_int_to_signed_char(unsigned int src) {
   // 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_TRUNCATION]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
-  // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_300_TRUNCATION]] 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 @@ signed char signed_int_to_signed_char(signed int src) {
   // 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_TRUNCATION]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
-  // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_400_TRUNCATION]] 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 @@ uint8_t uint32_to_uint8(uint32_t src) {
   // 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_TRUNCATION]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
-  // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_500_TRUNCATION]] 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]]:
diff --git a/test/CodeGen/catch-implicit-signed-integer-truncations-basics-negatives.c b/test/CodeGen/catch-implicit-signed-integer-truncations-basics-negatives.c
new file mode 100644 (file)
index 0000000..4ec4385
--- /dev/null
@@ -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;
+}
diff --git a/test/CodeGen/catch-implicit-signed-integer-truncations-basics.c b/test/CodeGen/catch-implicit-signed-integer-truncations-basics.c
new file mode 100644 (file)
index 0000000..a0fa2c3
--- /dev/null
@@ -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;
+}
diff --git a/test/CodeGen/catch-implicit-unsigned-integer-truncations-basics-negatives.c b/test/CodeGen/catch-implicit-unsigned-integer-truncations-basics-negatives.c
new file mode 100644 (file)
index 0000000..de6c098
--- /dev/null
@@ -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;
+}
diff --git a/test/CodeGen/catch-implicit-unsigned-integer-truncations-basics.c b/test/CodeGen/catch-implicit-unsigned-integer-truncations-basics.c
new file mode 100644 (file)
index 0000000..7eb0f0f
--- /dev/null
@@ -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 ba7676a3504a1f0938539c735914328357ee339e..2902fe1e884da80f314dfe682712d6459cda9069 100644 (file)
@@ -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 f2bf8fb6210831797f96bde5931e32dc19832686..51d910c304174c4604259f7055509e65b6edfea6 100644 (file)
 // 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}"}}