| /* { dg-do run } */ |
| /* { dg-require-effective-target hwaddress_exec } */ |
| |
| /* |
| Tests of nested funtions are: |
| 0) Accessing closed over variables works. |
| 1) Accesses outside of variables is caught. |
| 2) Accessing variable out of scope is caught. |
| |
| Here we test that accessing closed over variables works. |
| */ |
| |
| /* We need a second layer of indirection so that GCC doesn't notice we're |
| returning the address of a local variable and put 0 in it's place. */ |
| __attribute__((noinline)) |
| int *Ident(void *x) { |
| return x; |
| } |
| |
| int __attribute__ ((noinline)) |
| intermediate (void (*f) (int, char), |
| char num) |
| { |
| if (num == 1) |
| /* NOTE: We need to overrun by an amount greater than the "extra data" in a |
| nonlocal goto structure. The entire structure is allocated on the stack |
| with a single tag, which means hwasan can't tell if a closed-over buffer |
| was overrun by an amount small enough that the access was still to some |
| data in that nonlocal goto structure. */ |
| f (100, 100); |
| else |
| f (3, 100); |
| /* Just return something ... */ |
| return num % 3; |
| } |
| |
| int* __attribute__ ((noinline)) |
| nested_function (char num) |
| { |
| int big_array[16]; |
| int other_array[16]; |
| void store (int index, char value) |
| { big_array[index] = value; } |
| return Ident(&other_array[intermediate (store, num)]); |
| } |
| |
| #ifndef MAIN |
| int main () |
| { |
| nested_function (0); |
| return 0; |
| } |
| #endif |