[PATCH][RFC] Map -ftrapv to -fsanitize=signed-integer-overflow -fsanitize-undefined-trap-on-error
Martin Sebor
msebor@gmail.com
Mon Oct 25 16:45:33 GMT 2021
On 10/20/21 7:22 AM, Richard Biener via Gcc-patches wrote:
> This maps -ftrapv to -fsanitize=signed-integer-overflow
> -fsanitize-undefined-trap-on-error, effectively removing
> flag_trapv (or rather making it always false).
It sounds like C/C++ programmers might benefit from this change
but users of the option in other languages would not. I'm sure
they'd appreciate a heads up on the upcoming removal of a feature
so they could adjust to it. Issuing a warning would be one way
to give them such a heads up, while keeping the existing behavior
for a release, and then removing it.
>
> This has implications on language support - while -ftrapv
> was formerly universally available the mapping restricts it
> to the C family of frontends.
>
> It also raises questions on mixing -ftrapv with -fsanitize
> flags, specifically with other recovery options for the
> undefined sanitizer since -fsanitize-undefined-trap-on-error
> cannot be restricted to the signed-integer-overflow part at
> the moment. To more closely map behavior we could add
> -fsanitize=trapv where with a single option we could also
> simply alias -ftrapv to that.
>
> Code quality wise a simple signed add compiles to
>
> movl %edi, %eax
> addl %esi, %eax
> jo .L5
> ...
> .L5:
> ud2
>
> compared to
>
> call __addvsi3
>
> and it has less of the bugs -ftrapv has. The IL will
> not contain a PLUS_EXPR but a .UBSAN_CHECK_ADD internal
> function call which has rudimentary support throughout
> optimizers but is not recognized as possibly terminating
> the program so
>
> int foo (int i, int j, int *p, int k)
> {
> int tem = i + j;
> *p = 0;
> if (k)
> return tem;
> return 0;
> }
>
> will be optimized to perform the add only conditional
> and the possibly NULL *p dereference first (note the
> same happens with the "legacy" -ftrapv). The behavior
> with -fnon-call-exceptions is also different as the
> internal functions are marked as not throwing and
> as seen above the actual kind of trap can change (SIGILL
> vs. SIGABRT).
>
> One question is whether -ftrapv makes signed integer overflow
> well-defined (to trap)
Trapping isn't well-defined in the C/C++ sense of the word.
It's still undefined behavior, even if it's documented that
way. (Same way dereferencing a null pointer is undefined,
even if it results in SIGBUS.)
Martin
like -fwrapv makes it wrap. If so
> the the above behavior is ill-formed. Not sure how
> sanitizers position themselves with respect to this and
> whether the current behavior is OK there. The patch below
> instruments signed integer ops but leaves them undefined
> so the compiler still has to be careful as to not introduce
> new signed overflow (but at least that won't trap).
> Currently -fwrapv -fsanitize=signed-integer-overflow will
> not instrument any signed operations for example.
>
> I do consider the option to simply make -ftrapv do nothing
> but warn that people should use UBSAN - that wouldn't
> imply semantics are 1:1 the same (which they are not).
>
> Bootstrapped and tested on x86_64-unknown-linux-gnu, regresses
>
> FAIL: gcc.dg/vect/trapv-vect-reduc-4.c scan-tree-dump-times vect "Detected
> reduc
> tion\\\\." 3
> FAIL: gcc.dg/vect/trapv-vect-reduc-4.c scan-tree-dump-times vect "using an
> in-or
> der \\\\(fold-left\\\\) reduction" 1
> FAIL: gcc.dg/vect/trapv-vect-reduc-4.c scan-tree-dump-times vect
> "vectorized 3 l
> oops" 1
>
> where the vectorizer doesn't know the UBSAN IFNs.
>
> 2021-10-20 Richard Biener <rguenther@suse.de>
>
> * opts.c (common_handle_option): Handle -ftrapv like
> -fsanitize=signed-integer-overflow
> -fsanitize-undefined-trap-on-error and do not set
> flag_trapv.
> ---
> gcc/opts.c | 16 +++++++++++++++-
> 1 file changed, 15 insertions(+), 1 deletion(-)
>
> diff --git a/gcc/opts.c b/gcc/opts.c
> index 65fe192a198..909d2a031ff 100644
> --- a/gcc/opts.c
> +++ b/gcc/opts.c
> @@ -3022,7 +3022,21 @@ common_handle_option (struct gcc_options *opts,
>
> case OPT_ftrapv:
> if (value)
> - opts->x_flag_wrapv = 0;
> + {
> + opts->x_flag_wrapv = 0;
> + opts->x_flag_sanitize
> + = parse_sanitizer_options ("signed-integer-overflow",
> + loc, code, opts->x_flag_sanitize,
> + value, false);
> + if (!opts_set->x_flag_sanitize_undefined_trap_on_error)
> + opts->x_flag_sanitize_undefined_trap_on_error = 1;
> + /* This keeps overflow undefined and not trap. Specifically
> + it does no longer allow to catch exceptions together with
> + -fnon-call-exceptions. It also makes -ftrapv cease to
> + work with non-C-family languages since ubsan only works for
> + those. */
> + opts->x_flag_trapv = 0;
> + }
> break;
>
> case OPT_fstrict_overflow:
>
More information about the Gcc-patches
mailing list