Hi. Following patch handles various issues related to -fsanitize-recover* options:
1) -fsanitize-recover=unreachable and -fsanitize-recover=return are currently not reported as invalid options (error message is not displayed) 2) explanation of -fsanitize-recover is not precise (bounds-strict is not listed) 3) -fsanitize=leak is combinable with -fsanitize=address or -fsanitize=thread Patch can bootstrap on ppc64le-redhat-linux and survives regression tests. Ready to be installed? Martin
>From 077f6945e612f97ca16b792dd3f0740410b513af Mon Sep 17 00:00:00 2001 From: marxin <mli...@suse.cz> Date: Fri, 23 Sep 2016 10:16:10 +0200 Subject: [PATCH] Fix handling of -fsanitize-recover* options. gcc/ChangeLog: 2016-09-23 Martin Liska <mli...@suse.cz> * common.opt: Exclude SANITIZE_UNREACHABLE and SANITIZE_RETURN from default sanitize recover values. * doc/invoke.texi: Fix documentation related to -fsanitize=leak and -fsanitize-recover. * flag-types.h: Replace couple of 1 << x to 1UL << x, make it consistent. * opts.c (finish_options): Do a generic loop over options that can be recovered. (parse_sanitizer_options): Exclude SANITIZE_UNREACHABLE and SANITIZE_RETURN. (common_handle_option): Likewise. * opts.h: Declare can_recover to sanitizer_opts_s. --- gcc/common.opt | 2 +- gcc/doc/invoke.texi | 10 +-- gcc/flag-types.h | 32 ++++----- gcc/opts.c | 82 ++++++++++++---------- gcc/opts.h | 1 + .../c-c++-common/ubsan/sanitize-recover-1.c | 6 ++ .../c-c++-common/ubsan/sanitize-recover-2.c | 6 ++ .../c-c++-common/ubsan/sanitize-recover-3.c | 4 ++ .../c-c++-common/ubsan/sanitize-recover-4.c | 4 ++ .../c-c++-common/ubsan/sanitize-recover-5.c | 6 ++ .../c-c++-common/ubsan/sanitize-recover-6.c | 4 ++ 11 files changed, 99 insertions(+), 58 deletions(-) create mode 100644 gcc/testsuite/c-c++-common/ubsan/sanitize-recover-1.c create mode 100644 gcc/testsuite/c-c++-common/ubsan/sanitize-recover-2.c create mode 100644 gcc/testsuite/c-c++-common/ubsan/sanitize-recover-3.c create mode 100644 gcc/testsuite/c-c++-common/ubsan/sanitize-recover-4.c create mode 100644 gcc/testsuite/c-c++-common/ubsan/sanitize-recover-5.c create mode 100644 gcc/testsuite/c-c++-common/ubsan/sanitize-recover-6.c diff --git a/gcc/common.opt b/gcc/common.opt index 8c0885c..f35660f 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -228,7 +228,7 @@ unsigned int flag_sanitize ; What sanitizers should recover from errors Variable -unsigned int flag_sanitize_recover = SANITIZE_UNDEFINED | SANITIZE_NONDEFAULT | SANITIZE_KERNEL_ADDRESS +unsigned int flag_sanitize_recover = (SANITIZE_UNDEFINED | SANITIZE_NONDEFAULT | SANITIZE_KERNEL_ADDRESS) & ~(SANITIZE_UNREACHABLE | SANITIZE_RETURN) fsanitize-coverage=trace-pc Common Report Var(flag_sanitize_coverage) diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index d474da6..52804c0 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -10173,9 +10173,8 @@ supported options. @item -fsanitize=leak @opindex fsanitize=leak Enable LeakSanitizer, a memory leak detector. -This option only matters for linking of executables and if neither -@option{-fsanitize=address} nor @option{-fsanitize=thread} is used. In that -case the executable is linked against a library that overrides @code{malloc} +This option only matters for linking of executables and +the executable is linked against a library that overrides @code{malloc} and other allocator functions. See @uref{https://github.com/google/sanitizers/wiki/AddressSanitizerLeakSanitizer} for more details. The run-time behavior can be influenced using the @@ -10353,6 +10352,7 @@ and program then exits with a non-zero exit code. Currently this feature only works for @option{-fsanitize=undefined} (and its suboptions except for @option{-fsanitize=unreachable} and @option{-fsanitize=return}), @option{-fsanitize=float-cast-overflow}, @option{-fsanitize=float-divide-by-zero}, +@option{-fsanitize=bounds-strict}, @option{-fsanitize=kernel-address} and @option{-fsanitize=address}. For these sanitizers error recovery is turned on by default, except @option{-fsanitize=address}, for which this feature is experimental. @@ -10369,12 +10369,12 @@ setting the @code{halt_on_error} flag in the corresponding environment variable. Syntax without explicit @var{opts} parameter is deprecated. It is equivalent to @smallexample --fsanitize-recover=undefined,float-cast-overflow,float-divide-by-zero +-fsanitize-recover=undefined,float-cast-overflow,float-divide-by-zero,bounds-strict @end smallexample @noindent Similarly @option{-fno-sanitize-recover} is equivalent to @smallexample --fno-sanitize-recover=undefined,float-cast-overflow,float-divide-by-zero +-fno-sanitize-recover=undefined,float-cast-overflow,float-divide-by-zero,bounds-strict @end smallexample @item -fsanitize-undefined-trap-on-error diff --git a/gcc/flag-types.h b/gcc/flag-types.h index dd57e16..cd53ec3 100644 --- a/gcc/flag-types.h +++ b/gcc/flag-types.h @@ -203,25 +203,25 @@ enum vect_cost_model { /* Different instrumentation modes. */ enum sanitize_code { /* AddressSanitizer. */ - SANITIZE_ADDRESS = 1 << 0, - SANITIZE_USER_ADDRESS = 1 << 1, - SANITIZE_KERNEL_ADDRESS = 1 << 2, + SANITIZE_ADDRESS = 1UL<< 0, + SANITIZE_USER_ADDRESS = 1UL<< 1, + SANITIZE_KERNEL_ADDRESS = 1UL<< 2, /* ThreadSanitizer. */ - SANITIZE_THREAD = 1 << 3, + SANITIZE_THREAD = 1UL<< 3, /* LeakSanitizer. */ - SANITIZE_LEAK = 1 << 4, + SANITIZE_LEAK = 1UL<< 4, /* UndefinedBehaviorSanitizer. */ - SANITIZE_SHIFT = 1 << 5, - SANITIZE_DIVIDE = 1 << 6, - SANITIZE_UNREACHABLE = 1 << 7, - SANITIZE_VLA = 1 << 8, - SANITIZE_NULL = 1 << 9, - SANITIZE_RETURN = 1 << 10, - SANITIZE_SI_OVERFLOW = 1 << 11, - SANITIZE_BOOL = 1 << 12, - SANITIZE_ENUM = 1 << 13, - SANITIZE_FLOAT_DIVIDE = 1 << 14, - SANITIZE_FLOAT_CAST = 1 << 15, + 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, diff --git a/gcc/opts.c b/gcc/opts.c index f625973..d6cfd53 100644 --- a/gcc/opts.c +++ b/gcc/opts.c @@ -957,12 +957,11 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set, "are incompatible with -fsanitize=thread"); /* Error recovery is not allowed for LSan and TSan. */ - - if (opts->x_flag_sanitize_recover & SANITIZE_THREAD) - error_at (loc, "-fsanitize-recover=thread is not supported"); - - if (opts->x_flag_sanitize_recover & SANITIZE_LEAK) - error_at (loc, "-fsanitize-recover=leak is not supported"); + for (int i = 0; sanitizer_opts[i].name != NULL; ++i) + if ((opts->x_flag_sanitize_recover & sanitizer_opts[i].flag) + && !sanitizer_opts[i].can_recover) + error_at (loc, "-fsanitize-recover=%s is not supported", + sanitizer_opts[i].name); /* When instrumenting the pointers, we don't want to remove the null pointer checks. */ @@ -1448,33 +1447,36 @@ enable_fdo_optimizations (struct gcc_options *opts, /* -f{,no-}sanitize{,-recover}= suboptions. */ const struct sanitizer_opts_s sanitizer_opts[] = { -#define SANITIZER_OPT(name, flags) { #name, flags, sizeof #name - 1 } - SANITIZER_OPT (address, SANITIZE_ADDRESS | SANITIZE_USER_ADDRESS), - SANITIZER_OPT (kernel-address, SANITIZE_ADDRESS | SANITIZE_KERNEL_ADDRESS), - SANITIZER_OPT (thread, SANITIZE_THREAD), - SANITIZER_OPT (leak, SANITIZE_LEAK), - SANITIZER_OPT (shift, SANITIZE_SHIFT), - SANITIZER_OPT (integer-divide-by-zero, SANITIZE_DIVIDE), - SANITIZER_OPT (undefined, SANITIZE_UNDEFINED), - SANITIZER_OPT (unreachable, SANITIZE_UNREACHABLE), - SANITIZER_OPT (vla-bound, SANITIZE_VLA), - SANITIZER_OPT (return, SANITIZE_RETURN), - SANITIZER_OPT (null, SANITIZE_NULL), - SANITIZER_OPT (signed-integer-overflow, SANITIZE_SI_OVERFLOW), - SANITIZER_OPT (bool, SANITIZE_BOOL), - SANITIZER_OPT (enum, SANITIZE_ENUM), - SANITIZER_OPT (float-divide-by-zero, SANITIZE_FLOAT_DIVIDE), - SANITIZER_OPT (float-cast-overflow, SANITIZE_FLOAT_CAST), - SANITIZER_OPT (bounds, SANITIZE_BOUNDS), - SANITIZER_OPT (bounds-strict, SANITIZE_BOUNDS | SANITIZE_BOUNDS_STRICT), - SANITIZER_OPT (alignment, SANITIZE_ALIGNMENT), - SANITIZER_OPT (nonnull-attribute, SANITIZE_NONNULL_ATTRIBUTE), - SANITIZER_OPT (returns-nonnull-attribute, SANITIZE_RETURNS_NONNULL_ATTRIBUTE), - SANITIZER_OPT (object-size, SANITIZE_OBJECT_SIZE), - SANITIZER_OPT (vptr, SANITIZE_VPTR), - SANITIZER_OPT (all, ~0U), +#define SANITIZER_OPT(name, flags, recover) \ + { #name, flags, sizeof #name - 1, recover } + SANITIZER_OPT (address, SANITIZE_ADDRESS | SANITIZE_USER_ADDRESS, true), + SANITIZER_OPT (kernel-address, SANITIZE_ADDRESS | SANITIZE_KERNEL_ADDRESS, + true), + SANITIZER_OPT (thread, SANITIZE_THREAD, false), + SANITIZER_OPT (leak, SANITIZE_LEAK, false), + SANITIZER_OPT (shift, SANITIZE_SHIFT, true), + SANITIZER_OPT (integer-divide-by-zero, SANITIZE_DIVIDE, true), + SANITIZER_OPT (undefined, SANITIZE_UNDEFINED, true), + SANITIZER_OPT (unreachable, SANITIZE_UNREACHABLE, false), + SANITIZER_OPT (vla-bound, SANITIZE_VLA, true), + SANITIZER_OPT (return, SANITIZE_RETURN, false), + SANITIZER_OPT (null, SANITIZE_NULL, true), + SANITIZER_OPT (signed-integer-overflow, SANITIZE_SI_OVERFLOW, true), + SANITIZER_OPT (bool, SANITIZE_BOOL, true), + SANITIZER_OPT (enum, SANITIZE_ENUM, true), + SANITIZER_OPT (float-divide-by-zero, SANITIZE_FLOAT_DIVIDE, true), + SANITIZER_OPT (float-cast-overflow, SANITIZE_FLOAT_CAST, true), + SANITIZER_OPT (bounds, SANITIZE_BOUNDS, true), + SANITIZER_OPT (bounds-strict, SANITIZE_BOUNDS | SANITIZE_BOUNDS_STRICT, true), + SANITIZER_OPT (alignment, SANITIZE_ALIGNMENT, true), + SANITIZER_OPT (nonnull-attribute, SANITIZE_NONNULL_ATTRIBUTE, true), + SANITIZER_OPT (returns-nonnull-attribute, SANITIZE_RETURNS_NONNULL_ATTRIBUTE, + true), + SANITIZER_OPT (object-size, SANITIZE_OBJECT_SIZE, true), + SANITIZER_OPT (vptr, SANITIZE_VPTR, true), + SANITIZER_OPT (all, ~0U, true), #undef SANITIZER_OPT - { NULL, 0U, 0UL } + { NULL, 0U, 0UL, false } }; /* Parse comma separated sanitizer suboptions from P for option SCODE, @@ -1516,11 +1518,18 @@ parse_sanitizer_options (const char *p, location_t loc, int scode, error_at (loc, "-fsanitize=all option is not valid"); } else - flags |= ~(SANITIZE_USER_ADDRESS | SANITIZE_THREAD - | SANITIZE_LEAK); + flags |= ~(SANITIZE_THREAD | SANITIZE_LEAK + | SANITIZE_UNREACHABLE | SANITIZE_RETURN); } else if (value) - flags |= sanitizer_opts[i].flag; + { + flags |= sanitizer_opts[i].flag; + /* Do not enable -fsanitize-recover=unreachable and + -fsanitize-recover=return if -fsanitize-recover=undefined + is selected. */ + if (sanitizer_opts[i].flag == SANITIZE_UNDEFINED) + flags &= ~(SANITIZE_UNREACHABLE | SANITIZE_RETURN); + } else flags &= ~sanitizer_opts[i].flag; found = true; @@ -1770,7 +1779,8 @@ common_handle_option (struct gcc_options *opts, case OPT_fsanitize_recover: if (value) opts->x_flag_sanitize_recover - |= SANITIZE_UNDEFINED | SANITIZE_NONDEFAULT; + |= (SANITIZE_UNDEFINED | SANITIZE_NONDEFAULT) + & ~(SANITIZE_UNREACHABLE | SANITIZE_RETURN); else opts->x_flag_sanitize_recover &= ~(SANITIZE_UNDEFINED | SANITIZE_NONDEFAULT); diff --git a/gcc/opts.h b/gcc/opts.h index 4132432..b3e6435 100644 --- a/gcc/opts.h +++ b/gcc/opts.h @@ -414,6 +414,7 @@ extern const struct sanitizer_opts_s const char *const name; unsigned int flag; size_t len; + bool can_recover; } sanitizer_opts[]; extern void add_misspelling_candidates (auto_vec<char *> *candidates, diff --git a/gcc/testsuite/c-c++-common/ubsan/sanitize-recover-1.c b/gcc/testsuite/c-c++-common/ubsan/sanitize-recover-1.c new file mode 100644 index 0000000..4d8c27e --- /dev/null +++ b/gcc/testsuite/c-c++-common/ubsan/sanitize-recover-1.c @@ -0,0 +1,6 @@ +/* { dg-do compile } */ +/* { dg-options "-fsanitize-recover=unreachable" } */ + +int i; + +/* { dg-error "-fsanitize-recover=unreachable is not supported" "" { target *-*-* } 0 } */ diff --git a/gcc/testsuite/c-c++-common/ubsan/sanitize-recover-2.c b/gcc/testsuite/c-c++-common/ubsan/sanitize-recover-2.c new file mode 100644 index 0000000..e9849bd --- /dev/null +++ b/gcc/testsuite/c-c++-common/ubsan/sanitize-recover-2.c @@ -0,0 +1,6 @@ +/* { dg-do compile } */ +/* { dg-options "-fsanitize-recover=return" } */ + +int i; + +/* { dg-error "-fsanitize-recover=return is not supported" "" { target *-*-* } 0 } */ diff --git a/gcc/testsuite/c-c++-common/ubsan/sanitize-recover-3.c b/gcc/testsuite/c-c++-common/ubsan/sanitize-recover-3.c new file mode 100644 index 0000000..844f3fd --- /dev/null +++ b/gcc/testsuite/c-c++-common/ubsan/sanitize-recover-3.c @@ -0,0 +1,4 @@ +/* { dg-do compile } */ +/* { dg-options "-fsanitize-recover=all" } */ + +int i; diff --git a/gcc/testsuite/c-c++-common/ubsan/sanitize-recover-4.c b/gcc/testsuite/c-c++-common/ubsan/sanitize-recover-4.c new file mode 100644 index 0000000..45fa5b9 --- /dev/null +++ b/gcc/testsuite/c-c++-common/ubsan/sanitize-recover-4.c @@ -0,0 +1,4 @@ +/* { dg-do compile } */ +/* { dg-options "-fsanitize-recover=undefined" } */ + +int i; diff --git a/gcc/testsuite/c-c++-common/ubsan/sanitize-recover-5.c b/gcc/testsuite/c-c++-common/ubsan/sanitize-recover-5.c new file mode 100644 index 0000000..9c1ed32 --- /dev/null +++ b/gcc/testsuite/c-c++-common/ubsan/sanitize-recover-5.c @@ -0,0 +1,6 @@ +/* { dg-do compile } */ +/* { dg-options "-fsanitize-recover=undefined,unreachable" } */ + +int i; + +/* { dg-error "-fsanitize-recover=unreachable is not supported" "" { target *-*-* } 0 } */ diff --git a/gcc/testsuite/c-c++-common/ubsan/sanitize-recover-6.c b/gcc/testsuite/c-c++-common/ubsan/sanitize-recover-6.c new file mode 100644 index 0000000..e309e1b --- /dev/null +++ b/gcc/testsuite/c-c++-common/ubsan/sanitize-recover-6.c @@ -0,0 +1,4 @@ +/* { dg-do compile } */ +/* { dg-options "-fsanitize-recover=undefined,unreachable -fno-sanitize-recover=unreachable" } */ + +int i; -- 2.9.2