flag-types.h (enum sanitize_code): Add SANITIZE_SHIFT_BASE and SANITIZE_SHIFT_EXPONENT...
authorJakub Jelinek <jakub@redhat.com>
Wed, 9 Nov 2016 15:37:28 +0000 (16:37 +0100)
committerJakub Jelinek <jakub@gcc.gnu.org>
Wed, 9 Nov 2016 15:37:28 +0000 (16:37 +0100)
* flag-types.h (enum sanitize_code): Add SANITIZE_SHIFT_BASE
and SANITIZE_SHIFT_EXPONENT, change SANITIZE_SHIFT to bitwise
or of them, renumber other enumerators.
* opts.c (sanitizer_opts): Add shift-base and shift-exponent.
* doc/invoke.texi: Document -fsanitize=shift-base and
-fsanitize-shift-exponent, document -fsanitize=shift as
having those 2 suboptions.
c-family/
* c-ubsan.c (ubsan_instrument_shift): Handle split
-fsanitize=shift-base and -fsanitize=shift-exponent.
testsuite/
* gcc.dg/ubsan/c99-shift-3.c: New test.
* gcc.dg/ubsan/c99-shift-4.c: New test.
* gcc.dg/ubsan/c99-shift-5.c: New test.
* gcc.dg/ubsan/c99-shift-6.c: New test.

From-SVN: r242005

gcc/ChangeLog
gcc/c-family/ChangeLog
gcc/c-family/c-ubsan.c
gcc/doc/invoke.texi
gcc/flag-types.h
gcc/opts.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/ubsan/c99-shift-3.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/ubsan/c99-shift-4.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/ubsan/c99-shift-5.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/ubsan/c99-shift-6.c [new file with mode: 0644]

index 2188dbfe5e360a4ae234e1daeeb30188e0b3aea6..355148b2c724cdce625b0757a1676cc1d3c43512 100644 (file)
@@ -1,3 +1,13 @@
+2016-11-09  Jakub Jelinek  <jakub@redhat.com>
+
+       * flag-types.h (enum sanitize_code): Add SANITIZE_SHIFT_BASE
+       and SANITIZE_SHIFT_EXPONENT, change SANITIZE_SHIFT to bitwise
+       or of them, renumber other enumerators.
+       * opts.c (sanitizer_opts): Add shift-base and shift-exponent.
+       * doc/invoke.texi: Document -fsanitize=shift-base and
+       -fsanitize-shift-exponent, document -fsanitize=shift as
+       having those 2 suboptions.
+
 2016-11-09  Richard Biener  <rguenther@suse.de>
 
        * fold-const.c (tree_swap_operands_p): Remove unused arg.
index 5207c34c912a79eec6c10fac3c9814efd637d39f..89b3043ba48e05a6bf49fe0a5bffdba498fad94a 100644 (file)
@@ -1,3 +1,8 @@
+2016-11-09  Jakub Jelinek  <jakub@redhat.com>
+
+       * c-ubsan.c (ubsan_instrument_shift): Handle split
+       -fsanitize=shift-base and -fsanitize=shift-exponent.
+
 2016-11-07  Jason Merrill  <jason@redhat.com>
 
        * c.opt (Wc++1z-compat): New.
index 482cce19f3c387a0ca0430a5acb4049963503f70..6f93d80a74600dbf35f9e220814c135d5c9ca92d 100644 (file)
@@ -130,7 +130,8 @@ ubsan_instrument_shift (location_t loc, enum tree_code code,
   /* If this is not a signed operation, don't perform overflow checks.
      Also punt on bit-fields.  */
   if (TYPE_OVERFLOW_WRAPS (type0)
-      || GET_MODE_BITSIZE (TYPE_MODE (type0)) != TYPE_PRECISION (type0))
+      || GET_MODE_BITSIZE (TYPE_MODE (type0)) != TYPE_PRECISION (type0)
+      || (flag_sanitize & SANITIZE_SHIFT_BASE) == 0)
     ;
 
   /* For signed x << y, in C99/C11, the following:
@@ -171,8 +172,27 @@ ubsan_instrument_shift (location_t loc, enum tree_code code,
   /* In case we have a SAVE_EXPR in a conditional context, we need to
      make sure it gets evaluated before the condition.  */
   t = fold_build2 (COMPOUND_EXPR, TREE_TYPE (t), unshare_expr (op0), t);
-  t = fold_build2 (TRUTH_OR_EXPR, boolean_type_node, t,
-                  tt ? tt : integer_zero_node);
+
+  enum sanitize_code recover_kind = SANITIZE_SHIFT_EXPONENT;
+  tree else_t = void_node;
+  if (tt)
+    {
+      if ((flag_sanitize & SANITIZE_SHIFT_EXPONENT) == 0)
+       {
+         t = fold_build1 (TRUTH_NOT_EXPR, boolean_type_node, t);
+         t = fold_build2 (TRUTH_AND_EXPR, boolean_type_node, t, tt);
+         recover_kind = SANITIZE_SHIFT_BASE;
+       }
+      else
+       {
+         if (flag_sanitize_undefined_trap_on_error
+             || ((!(flag_sanitize_recover & SANITIZE_SHIFT_EXPONENT))
+                 == (!(flag_sanitize_recover & SANITIZE_SHIFT_BASE))))
+           t = fold_build2 (TRUTH_OR_EXPR, boolean_type_node, t, tt);
+         else
+           else_t = tt;
+       }
+    }
 
   if (flag_sanitize_undefined_trap_on_error)
     tt = build_call_expr_loc (loc, builtin_decl_explicit (BUILT_IN_TRAP), 0);
@@ -185,7 +205,7 @@ ubsan_instrument_shift (location_t loc, enum tree_code code,
       data = build_fold_addr_expr_loc (loc, data);
 
       enum built_in_function bcode
-       = (flag_sanitize_recover & SANITIZE_SHIFT)
+       = (flag_sanitize_recover & recover_kind)
          ? BUILT_IN_UBSAN_HANDLE_SHIFT_OUT_OF_BOUNDS
          : BUILT_IN_UBSAN_HANDLE_SHIFT_OUT_OF_BOUNDS_ABORT;
       tt = builtin_decl_explicit (bcode);
@@ -193,8 +213,22 @@ ubsan_instrument_shift (location_t loc, enum tree_code code,
       op1 = unshare_expr (op1);
       tt = build_call_expr_loc (loc, tt, 3, data, ubsan_encode_value (op0),
                                ubsan_encode_value (op1));
+      if (else_t != void_node)
+       {
+         bcode = (flag_sanitize_recover & SANITIZE_SHIFT_BASE)
+                 ? BUILT_IN_UBSAN_HANDLE_SHIFT_OUT_OF_BOUNDS
+                 : BUILT_IN_UBSAN_HANDLE_SHIFT_OUT_OF_BOUNDS_ABORT;
+         tree else_tt = builtin_decl_explicit (bcode);
+         op0 = unshare_expr (op0);
+         op1 = unshare_expr (op1);
+         else_tt = build_call_expr_loc (loc, else_tt, 3, data,
+                                        ubsan_encode_value (op0),
+                                        ubsan_encode_value (op1));
+         else_t = fold_build3 (COND_EXPR, void_type_node, else_t,
+                               else_tt, void_node);
+       }
     }
-  t = fold_build3 (COND_EXPR, void_type_node, t, tt, void_node);
+  t = fold_build3 (COND_EXPR, void_type_node, t, tt, else_t);
 
   return t;
 }
index 17c5c225d0c98b8e9ecffecda5985024ffaa12d0..76b854081bbf91850a96026f91e709ff537f2ac9 100644 (file)
@@ -10560,6 +10560,21 @@ at runtime.  Current suboptions are:
 This option enables checking that the result of a shift operation is
 not undefined.  Note that what exactly is considered undefined differs
 slightly between C and C++, as well as between ISO C90 and C99, etc.
+This option has two suboptions, @option{-fsanitize=shift-base} and
+@option{-fsanitize=shift-exponent}.
+
+@item -fsanitize=shift-exponent
+@opindex fsanitize=shift-exponent
+This option enables checking that the second argument of a shift operation
+is not negative and is smaller than the precision of the promoted first
+argument.
+
+@item -fsanitize=shift-base
+@opindex fsanitize=shift-base
+If the second argument of a shift operation is within range, check that the
+result of a shift operation is not undefined.  Note that what exactly is
+considered undefined differs slightly between C and C++, as well as between
+ISO C90 and C99, etc.
 
 @item -fsanitize=integer-divide-by-zero
 @opindex fsanitize=integer-divide-by-zero
index 816df6b4ad987752029eab6f418ca4e3bd52e6a3..6c5a4cc93461d9edb1605fac916541c4aa88fcf2 100644 (file)
@@ -211,24 +211,26 @@ enum sanitize_code {
   /* LeakSanitizer.  */
   SANITIZE_LEAK = 1UL << 4,
   /* UndefinedBehaviorSanitizer.  */
-  SANITIZE_SHIFT = 1UL << 5,
-  SANITIZE_DIVIDE = 1UL << 6,
-  SANITIZE_UNREACHABLE = 1UL << 7,
-  SANITIZE_VLA = 1UL << 8,
-  SANITIZE_NULL = 1UL << 9,
-  SANITIZE_RETURN = 1UL << 10,
-  SANITIZE_SI_OVERFLOW = 1UL << 11,
-  SANITIZE_BOOL = 1UL << 12,
-  SANITIZE_ENUM = 1UL << 13,
-  SANITIZE_FLOAT_DIVIDE = 1UL << 14,
-  SANITIZE_FLOAT_CAST = 1UL << 15,
-  SANITIZE_BOUNDS = 1UL << 16,
-  SANITIZE_ALIGNMENT = 1UL << 17,
-  SANITIZE_NONNULL_ATTRIBUTE = 1UL << 18,
-  SANITIZE_RETURNS_NONNULL_ATTRIBUTE = 1UL << 19,
-  SANITIZE_OBJECT_SIZE = 1UL << 20,
-  SANITIZE_VPTR = 1UL << 21,
-  SANITIZE_BOUNDS_STRICT = 1UL << 22,
+  SANITIZE_SHIFT_BASE = 1UL << 5,
+  SANITIZE_SHIFT_EXPONENT = 1UL << 6,
+  SANITIZE_DIVIDE = 1UL << 7,
+  SANITIZE_UNREACHABLE = 1UL << 8,
+  SANITIZE_VLA = 1UL << 9,
+  SANITIZE_NULL = 1UL << 10,
+  SANITIZE_RETURN = 1UL << 11,
+  SANITIZE_SI_OVERFLOW = 1UL << 12,
+  SANITIZE_BOOL = 1UL << 13,
+  SANITIZE_ENUM = 1UL << 14,
+  SANITIZE_FLOAT_DIVIDE = 1UL << 15,
+  SANITIZE_FLOAT_CAST = 1UL << 16,
+  SANITIZE_BOUNDS = 1UL << 17,
+  SANITIZE_ALIGNMENT = 1UL << 18,
+  SANITIZE_NONNULL_ATTRIBUTE = 1UL << 19,
+  SANITIZE_RETURNS_NONNULL_ATTRIBUTE = 1UL << 20,
+  SANITIZE_OBJECT_SIZE = 1UL << 21,
+  SANITIZE_VPTR = 1UL << 22,
+  SANITIZE_BOUNDS_STRICT = 1UL << 23,
+  SANITIZE_SHIFT = SANITIZE_SHIFT_BASE | SANITIZE_SHIFT_EXPONENT,
   SANITIZE_UNDEFINED = SANITIZE_SHIFT | SANITIZE_DIVIDE | SANITIZE_UNREACHABLE
                       | SANITIZE_VLA | SANITIZE_NULL | SANITIZE_RETURN
                       | SANITIZE_SI_OVERFLOW | SANITIZE_BOOL | SANITIZE_ENUM
index 2f230cea315fd21df3eebfe300c9f8af63bb31d4..d2d6100c0f7c76c799146e97a1303a587addf67d 100644 (file)
@@ -1477,6 +1477,8 @@ const struct sanitizer_opts_s sanitizer_opts[] =
   SANITIZER_OPT (thread, SANITIZE_THREAD, false),
   SANITIZER_OPT (leak, SANITIZE_LEAK, false),
   SANITIZER_OPT (shift, SANITIZE_SHIFT, true),
+  SANITIZER_OPT (shift-base, SANITIZE_SHIFT_BASE, true),
+  SANITIZER_OPT (shift-exponent, SANITIZE_SHIFT_EXPONENT, true),
   SANITIZER_OPT (integer-divide-by-zero, SANITIZE_DIVIDE, true),
   SANITIZER_OPT (undefined, SANITIZE_UNDEFINED, true),
   SANITIZER_OPT (unreachable, SANITIZE_UNREACHABLE, false),
index 5fb53383b5d6780de4292ff0cb4d3ec345d46385..dd221bbb136bb7426402ceb5af1798c9902fa516 100644 (file)
@@ -1,3 +1,10 @@
+2016-11-09  Jakub Jelinek  <jakub@redhat.com>
+
+       * gcc.dg/ubsan/c99-shift-3.c: New test.
+       * gcc.dg/ubsan/c99-shift-4.c: New test.
+       * gcc.dg/ubsan/c99-shift-5.c: New test.
+       * gcc.dg/ubsan/c99-shift-6.c: New test.
+
 2016-11-09  Martin Liska  <mliska@suse.cz>
 
        * gcc.dg/tree-ssa/builtins-folding-generic.c (main): Add new
diff --git a/gcc/testsuite/gcc.dg/ubsan/c99-shift-3.c b/gcc/testsuite/gcc.dg/ubsan/c99-shift-3.c
new file mode 100644 (file)
index 0000000..ebb4f66
--- /dev/null
@@ -0,0 +1,18 @@
+/* { dg-do run } */
+/* { dg-options "-fsanitize=shift-base -fno-sanitize=shift-exponent -w -std=c99" } */
+
+int
+main (void)
+{
+  int a = -42;
+  int b = -43;
+  volatile int c = 129;
+  int d = 1;
+  a << 1;
+  b << c;
+  a << 1;
+  d <<= 31;
+}
+/* { dg-output "left shift of negative value -42\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*left shift of negative value -42\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*left shift of 1 by 31 places cannot be represented in type 'int'" } */
diff --git a/gcc/testsuite/gcc.dg/ubsan/c99-shift-4.c b/gcc/testsuite/gcc.dg/ubsan/c99-shift-4.c
new file mode 100644 (file)
index 0000000..95c9616
--- /dev/null
@@ -0,0 +1,18 @@
+/* { dg-do run } */
+/* { dg-options "-fsanitize=shift-exponent -fno-sanitize=shift-base -w -std=c99" } */
+
+int
+main (void)
+{
+  int a = -42;
+  int b = -43;
+  volatile int c = 129;
+  int d = 1;
+  b << c;
+  a << 1;
+  a << 1;
+  d <<= 31;
+  b << (c + 1);
+}
+/* { dg-output "shift exponent 129 is too large for \[^\n\r]*-bit type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*shift exponent 130 is too large for \[^\n\r]*-bit type 'int'" } */
diff --git a/gcc/testsuite/gcc.dg/ubsan/c99-shift-5.c b/gcc/testsuite/gcc.dg/ubsan/c99-shift-5.c
new file mode 100644 (file)
index 0000000..0697997
--- /dev/null
@@ -0,0 +1,21 @@
+/* { dg-do run } */
+/* { dg-shouldfail "ubsan" } */
+/* { dg-options "-fsanitize=shift -fsanitize-recover=shift-base -fno-sanitize-recover=shift-exponent -w -std=c99" } */
+
+int
+main (void)
+{
+  int a = -42;
+  int b = -43;
+  volatile int c = 129;
+  int d = 1;
+  a << 1;
+  a << 1;
+  d <<= 31;
+  b << c;
+  a << 1;
+}
+/* { dg-output "left shift of negative value -42\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*left shift of negative value -42\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*left shift of 1 by 31 places cannot be represented in type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*shift exponent 129 is too large for \[^\n\r]*-bit type 'int'" } */
diff --git a/gcc/testsuite/gcc.dg/ubsan/c99-shift-6.c b/gcc/testsuite/gcc.dg/ubsan/c99-shift-6.c
new file mode 100644 (file)
index 0000000..8bf700c
--- /dev/null
@@ -0,0 +1,18 @@
+/* { dg-do run } */
+/* { dg-shouldfail "ubsan" } */
+/* { dg-options "-fsanitize=shift -fsanitize-recover=shift-exponent -fno-sanitize-recover=shift-base -w -std=c99" } */
+
+int
+main (void)
+{
+  int a = -42;
+  int b = -43;
+  volatile int c = 129;
+  1 << c;
+  1 << (c + 1);
+  a << 1;
+  b << 1;
+}
+/* { dg-output "shift exponent 129 is too large for \[^\n\r]*-bit type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*shift exponent 130 is too large for \[^\n\r]*-bit type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*left shift of negative value -42\[^\n\r]*(\n|\r\n|\r)" } */