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)