1 | // Test that use-after-return works with arguments passed by value. |
2 | // RUN: %clangxx_asan -O0 %s -o %t |
3 | // RUN: %env_asan_opts=detect_stack_use_after_return=0 %run %t 2>&1 | \ |
4 | // RUN: FileCheck --check-prefix=CHECK-NO-UAR %s |
5 | // RUN: not %env_asan_opts=detect_stack_use_after_return=1 %run %t 2>&1 | \ |
6 | // RUN: FileCheck --check-prefix=CHECK-UAR %s |
7 | // RUN: %clangxx_asan -O0 %s -o %t -fsanitize-address-use-after-return=never && \ |
8 | // RUN: %run %t 2>&1 | FileCheck --check-prefix=CHECK-NO-UAR %s |
9 | // RUN: %clangxx_asan -O0 %s -o %t -fsanitize-address-use-after-return=always && \ |
10 | // RUN: not %run %t 2>&1 | FileCheck --check-prefix=CHECK-UAR %s |
11 | // |
12 | // On several architectures, the IR does not use byval arguments for foo() and |
13 | // instead creates a copy in main() and gives foo() a pointer to the copy. In |
14 | // that case, ASAN has nothing to poison on return from foo() and will not |
15 | // detect the UAR. |
16 | // REQUIRES: x86_64-target-arch, linux, !android |
17 | |
18 | #include <cstdio> |
19 | |
20 | struct A { |
21 | int a[8]; |
22 | }; |
23 | |
24 | A *foo(A a) { |
25 | return &a; |
26 | } |
27 | |
28 | int main() { |
29 | A *a = foo(a: A()); |
30 | a->a[0] = 7; |
31 | std::fprintf(stderr, "\n" ); // Ensures some output is generated for FileCheck |
32 | // to verify in the case where UAR is not |
33 | // detected. |
34 | } |
35 | |
36 | // CHECK-NO-UAR-NOT: ERROR: AddressSanitizer: stack-use-after-return |
37 | // CHECK-NO-UAR-NOT: WRITE of size 4 at |
38 | // CHECK-NO-UAR-NOT: Memory access at offset {{[0-9]+}} is inside this variable |
39 | // |
40 | // CHECK-UAR: ERROR: AddressSanitizer: stack-use-after-return |
41 | // CHECK-UAR: WRITE of size 4 at |
42 | // CHECK-UAR: Memory access at offset {{[0-9]+}} is inside this variable |
43 | |