+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.
+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.
/* 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:
/* 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);
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);
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;
}
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
/* 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
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),
+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
--- /dev/null
+/* { 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'" } */
--- /dev/null
+/* { 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'" } */
--- /dev/null
+/* { 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'" } */
--- /dev/null
+/* { 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)" } */