On 6/27/22 11:44, Jakub Jelinek wrote:
On Wed, Jun 22, 2022 at 12:04:59AM -0400, Jason Merrill wrote:
On 6/20/22 16:16, Jason Merrill wrote:
On 6/20/22 07:05, Jakub Jelinek wrote:
On Fri, Jun 17, 2022 at 05:20:02PM -0400, Jason Merrill wrote:
Related to PR104642, the current situation where we get less
return checking
with just -fsanitize=unreachable than no sanitize flags seems
undesirable; I
propose that we do return checking when -fsanitize=unreachable.
__builtin_unreachable itself (unless turned into trap or
__ubsan_handle_builtin_unreachable) is not any kind of return
checking, it
is just an optimization.
Yes, but I'm talking about "when -fsanitize=unreachable".
The usual case is that people just use -fsanitize=undefined
and get both return and unreachable sanitization, for fall through
into end of functions returning non-void done through return sanitization.
In the rare case people use something different like
-fsanitize=undefined -fno-sanitize=return
or
-fsanitize=unreachable
etc., they presumably don't want the fall through from end of function
diagnosed at runtime.
I disagree with this assumption for the second case; it seems much more
likely to me that the user just wasn't thinking about needing to also
mention return. Missing return is a logical subset of unreachable; if
we sanitize all the other __builtin_unreachable introduced by the
compiler, why in the world would we want to leave out this one that is
such a frequent error?
Full -fsanitize=undefined is much higher overhead than just
-fsanitize=unreachable, which introduces no extra checks. And adding
return checking to unreachable is essentially zero overhead. I can't
imagine any reason to want to check unreachable points EXCEPT for
missing return.
I think the behavior we want is:
1) -fsanitize=return is on -> use ubsan_instrument_return
(__ubsan_missing_return_data or __builtin_trap depending on
-fsanitize-trap=return); otherwise
2) -funreachable-traps is on (from -O0/-Og by default or explicit),
emit __builtin_trap; otherwise
3) -fsanitize=unreachable is on, not emit anything (__builtin_unreachable
would be just an optimization, but user asked not to instrument returns,
only unreachable, so honor user's decision and avoid confusion); otherwise
> 4) -O0 is on, not emit anything (__builtin_unreachable wouldn't be much
of an optimization, just surprising and hard to debug effect); otherwise
5) emit __builtin_unreachable
Current trunk with your PR104642 fix in implements 1), will do 2)
only if -fsanitize=unreachable is not on, will do 3), will do 4) and 5).
So, I'd change cp-gimplify.cc (cp_maybe_instrument_return), change:
if (!sanitize_flags_p (SANITIZE_RETURN, fndecl)
&& ((!optimize && !flag_unreachable_traps)
|| sanitize_flags_p (SANITIZE_UNREACHABLE, fndecl)))
return;
to
if (!sanitize_flags_p (SANITIZE_RETURN, fndecl)
&& !flag_unreachable_traps
&& (!optimize || sanitize_flags_p (SANITIZE_UNREACHABLE, fndecl)))
return;
and
if (sanitize_flags_p (SANITIZE_RETURN, fndecl))
t = ubsan_instrument_return (loc);
else
t = build_builtin_unreachable (BUILTINS_LOCATION);
to
if (sanitize_flags_p (SANITIZE_RETURN, fndecl))
t = ubsan_instrument_return (loc);
else if (flag_unreachable_traps)
t = build_call_expr_loc (BUILTINS_LOCATION,
builtin_decl_explicit (BUILT_IN_TRAP), 0);
else
t = build_builtin_unreachable (BUILTINS_LOCATION);
Jakub