diff options
Diffstat (limited to 'SingleSource/Regression/C/gcc-c-torture/execute/pr17377.c')
-rw-r--r-- | SingleSource/Regression/C/gcc-c-torture/execute/pr17377.c | 60 |
1 files changed, 60 insertions, 0 deletions
diff --git a/SingleSource/Regression/C/gcc-c-torture/execute/pr17377.c b/SingleSource/Regression/C/gcc-c-torture/execute/pr17377.c new file mode 100644 index 00000000..11094d1b --- /dev/null +++ b/SingleSource/Regression/C/gcc-c-torture/execute/pr17377.c @@ -0,0 +1,60 @@ +/* PR target/17377 + Bug in code emitted by "return" pattern on CRIS: missing pop of + forced return address on stack. */ +/* { dg-require-effective-target return_address } */ +int calls = 0; + +void *f (int) __attribute__ ((__noinline__)); +void * +f (int i) +{ + /* The code does a little brittle song and dance to trig the "return" + pattern instead of the function epilogue. This must still be a + leaf function for the bug to be exposed. */ + + if (calls++ == 0) + return __builtin_return_address (0); + + switch (i) + { + case 1: + return f; + case 0: + return __builtin_return_address (0); + } + return 0; +} + +int x; + +void *y (int i) __attribute__ ((__noinline__,__noclone__)); +void * +y (int i) +{ + x = 0; + + /* This must not be a sibling call: the return address must appear + constant for different calls to this function. Postincrementing x + catches otherwise unidentified multiple returns (e.g. through the + return-address register and then this epilogue popping the address + stored on stack in "f"). */ + return (char *) f (i) + x++; +} + +int +main (void) +{ + void *v = y (4); + if (y (1) != f + /* Can't reasonably check the validity of the return address + above, but it's not that important: the test-case will probably + crash on the first call to f with the bug present, or it will + run wild including returning early (in y or here), so we also + try and check the number of calls. */ + || y (0) != v + || y (3) != 0 + || y (-1) != 0 + || calls != 5) + abort (); + exit (0); +} |