/* { dg-do run } */ /* { dg-options "-fstrub=strict" } */ /* { dg-require-effective-target strub } */ /* Check that a non-strub function leaves a string behind in the stack, and that equivalent strub functions don't. Allow red zones to be used. */ const char test_string[] = "\x55\xde\xad\xbe\xef\xc0\x1d\xca\xfe\x55\xaa"; /* Pad before and after the string on the stack, so that it's not overwritten by regular stack use. */ #define PAD 7 static inline __attribute__ ((__always_inline__, __strub__ ("callable"))) char * leak_string (void) { int len = sizeof (test_string); asm ("" : "+rm" (len)); char s[2 * PAD + 1][len]; __builtin_strcpy (s[PAD], test_string); asm ("" : "+m" (s)); return (char *) __builtin_stack_address (); } static inline __attribute__ ((__always_inline__)) int look_for_string (char *e) { char *p = (char *) __builtin_stack_address (); if (p == e) __builtin_abort (); if (p > e) { char *q = p; p = e; e = q; } for (char *re = e - sizeof (test_string); p < re; p++) for (int i = 0; p[i] == test_string[i]; i++) if (i == sizeof (test_string) - 1) return i; return 0; } static __attribute__ ((__noinline__, __noclone__)) char * callable () { return leak_string (); } static __attribute__ ((__strub__ ("at-calls"))) char * at_calls () { return leak_string (); } static __attribute__ ((__strub__ ("internal"))) char * internal () { return leak_string (); } int main () { /* Since these test check stack contents above the top of the stack, an unexpected asynchronous signal or interrupt might overwrite the bits we expect to find and cause spurious fails. Tolerate one such overall spurious fail by retrying. */ int i = 1; while (!look_for_string (callable ())) if (!i--) __builtin_abort (); while (look_for_string (at_calls ())) if (!i--) __builtin_abort (); while (look_for_string (internal ())) if (!i--) __builtin_abort (); __builtin_exit (0); }