flag-types.h (enum sanitize_code): Add SANITIZE_SHIFT_BASE and SANITIZE_SHIFT_EXPONENT...
* 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
This commit is contained in:
parent
14e7281244
commit
2e955d50a9
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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),
|
||||
|
@ -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
|
||||
|
18
gcc/testsuite/gcc.dg/ubsan/c99-shift-3.c
Normal file
18
gcc/testsuite/gcc.dg/ubsan/c99-shift-3.c
Normal file
@ -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'" } */
|
18
gcc/testsuite/gcc.dg/ubsan/c99-shift-4.c
Normal file
18
gcc/testsuite/gcc.dg/ubsan/c99-shift-4.c
Normal file
@ -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'" } */
|
21
gcc/testsuite/gcc.dg/ubsan/c99-shift-5.c
Normal file
21
gcc/testsuite/gcc.dg/ubsan/c99-shift-5.c
Normal file
@ -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'" } */
|
18
gcc/testsuite/gcc.dg/ubsan/c99-shift-6.c
Normal file
18
gcc/testsuite/gcc.dg/ubsan/c99-shift-6.c
Normal file
@ -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)" } */
|
Loading…
Reference in New Issue
Block a user