On Thu, 12 Jun 2025, Jakub Jelinek wrote:

> Hi!
> 
> These testcases show another problem with -fsanitize=address
> vs. musttail tail calls.  In particular, there can be
>   .ASAN_MARK (POISON, &a, 4);
> etc. calls after a tail call and those just prevent the tailc pass
> to mark the musttail calls as [tail call].
> Normally, the sanopt pass (which comes after tailc) will optimize those
> away, the optimization is if there are no .ASAN_CHECK calls or normal
> function calls dominated by those .ASAN_MARK (POSION, ...) calls, the
> poison is not needed, because in the epilog sequence (the one dealt with
> in the patch posted earlier today) all the stack slots are unpoisoned anyway
> (or poisoned for use-after-return).
> Unlike __builtin_tsan_exit_function, .ASAN_MARK is not a real function
> and is always expanded inline, so can be never tail called successfully,
> so the patch just ignores those for the cfun->has_musttail && diag_musttail
> cases.  If there is a non-musttail call, it will fail worst case during
> expansion because there is the epilog asan sequence.
> 
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk
> and 15.2 later?

OK.

Richard.

> 2025-06-12  Jakub Jelinek  <ja...@redhat.com>
> 
>       PR middle-end/120608
>       * tree-tailcall.cc (empty_eh_cleanup): Ignore .ASAN_MARK (POISON)
>       internal calls for the cfun->has_musttail case and diag_musttail.
>       (find_tail_calls): Likewise.
> 
>       * c-c++-common/asan/pr120608-1.c: New test.
>       * c-c++-common/asan/pr120608-2.c: New test.
> 
> --- gcc/tree-tailcall.cc.jj   2025-05-01 08:25:46.968898135 +0200
> +++ gcc/tree-tailcall.cc      2025-06-12 14:52:52.171918526 +0200
> @@ -528,6 +528,10 @@ empty_eh_cleanup (basic_block bb, int *e
>         *eh_has_tsan_func_exit = 1;
>         continue;
>       }
> +      if (eh_has_tsan_func_exit
> +       && sanitize_flags_p (SANITIZE_ADDRESS)
> +       && asan_mark_p (g, ASAN_MARK_POISON))
> +     continue;
>        if (is_gimple_resx (g) && stmt_can_throw_external (cfun, g))
>       return true;
>        return false;
> @@ -619,6 +623,12 @@ find_tail_calls (basic_block bb, struct
>           continue;
>       }
>  
> +      if (cfun->has_musttail
> +       && sanitize_flags_p (SANITIZE_ADDRESS)
> +       && asan_mark_p (stmt, ASAN_MARK_POISON)
> +       && diag_musttail)
> +     continue;
> +
>        if (!last_stmt)
>       last_stmt = stmt;
>        /* Check for a call.  */
> @@ -995,6 +1005,12 @@ find_tail_calls (basic_block bb, struct
>         continue;
>       }
>  
> +      if (cfun->has_musttail
> +       && sanitize_flags_p (SANITIZE_ADDRESS)
> +       && asan_mark_p (stmt, ASAN_MARK_POISON)
> +       && diag_musttail)
> +     continue;
> +
>        if (gimple_code (stmt) != GIMPLE_ASSIGN)
>       {
>         maybe_error_musttail (call, _("unhandled code after call"),
> --- gcc/testsuite/c-c++-common/asan/pr120608-1.c.jj   2025-06-12 
> 15:09:45.622485409 +0200
> +++ gcc/testsuite/c-c++-common/asan/pr120608-1.c      2025-06-12 
> 15:14:12.066955322 +0200
> @@ -0,0 +1,43 @@
> +/* PR middle-end/120608 */
> +/* { dg-do run { target musttail } } */
> +/* { dg-options "-O2 -fsanitize=address" } */
> +
> +__attribute__((noipa)) void
> +foo (int *x, int *y, int *z)
> +{
> +  ++x[0];
> +  ++y[0];
> +  ++z[0];
> +}
> +
> +__attribute__((noipa)) void
> +bar (int *x, int *y, int *z)
> +{
> +  if (x || y || z)
> +    __builtin_abort ();
> +}
> +
> +__attribute__((noipa)) void
> +baz (int *x, int *y, int *z)
> +{
> +  (void) x; (void) y; (void) z;
> +  int a = 42, b = -42, c = 0;
> +  foo (&a, &b, &c);
> +  [[gnu::musttail]] return bar (0, 0, 0);
> +}
> +
> +__attribute__((noipa)) void
> +qux (int *x, int *y, int *z)
> +{
> +  (void) x; (void) y; (void) z;
> +  int a = 42, b = -42, c = 0;
> +  foo (&a, &b, &c);
> +  [[gnu::musttail]] return bar (0, 0, 0);
> +}
> +
> +int
> +main ()
> +{
> +  baz (0, 0, 0);
> +  qux (0, 0, 0);
> +}
> --- gcc/testsuite/c-c++-common/asan/pr120608-2.c.jj   2025-06-12 
> 15:13:19.494651848 +0200
> +++ gcc/testsuite/c-c++-common/asan/pr120608-2.c      2025-06-12 
> 15:27:12.930602784 +0200
> @@ -0,0 +1,39 @@
> +/* PR middle-end/120608 */
> +/* { dg-do run { target musttail } } */
> +/* { dg-options "-O2 -fsanitize=address" } */
> +/* { dg-set-target-env-var ASAN_OPTIONS "detect_stack_use_after_return=1" } 
> */
> +/* { dg-shouldfail "asan" } */
> +
> +__attribute__((noipa)) void
> +foo (int *x, int *y, int *z)
> +{
> +  ++x[0];
> +  ++y[0];
> +  ++z[0];
> +}
> +
> +__attribute__((noipa)) void
> +bar (int *x, int *y, int *z)
> +{
> +  volatile int a = x[0] + y[0] + z[0];
> +}
> +
> +__attribute__((noipa)) void
> +baz (int *x, int *y, int *z)
> +{
> +  (void) x; (void) y; (void) z;
> +  int a = 42, b = -42, c = 0;
> +  foo (&a, &b, &c);
> +  [[gnu::musttail]] return bar (&a, &b, &c); /* { dg-warning "address of 
> automatic variable 'a' passed to 'musttail' call argument" } */
> +}                                            /* { dg-warning "address of 
> automatic variable 'b' passed to 'musttail' call argument" "" { target *-*-* 
> } .-1 } */
> +                                             /* { dg-warning "address of 
> automatic variable 'c' passed to 'musttail' call argument" "" { target *-*-* 
> } .-2 } */
> +
> +int
> +main ()
> +{
> +  baz (0, 0, 0);
> +}
> +
> +// { dg-output "ERROR: AddressSanitizer: stack-use-after-return on 
> address.*(\n|\r\n|\r)" }
> +// { dg-output "READ of size .*" }
> +// { dg-output ".*'a' \\(line 25\\) <== Memory access at offset \[0-9\]* is 
> inside this variable.*" }
> 
>       Jakub
> 
> 

-- 
Richard Biener <rguent...@suse.de>
SUSE Software Solutions Germany GmbH,
Frankenstrasse 146, 90461 Nuernberg, Germany;
GF: Ivo Totev, Andrew McDonald, Werner Knoblich; (HRB 36809, AG Nuernberg)

Reply via email to