xref: /llvm-project/compiler-rt/test/asan/TestCases/Posix/stack-use-after-return.cpp (revision abd09754edf156bf8c36ac6f52bf003706977b03)
1 // RUN: %clangxx_asan  -O0 %s -pthread -o %t && %env_asan_opts=detect_stack_use_after_return=1 not %run %t 2>&1 | FileCheck %s
2 // RUN: %clangxx_asan  -O1 %s -pthread -o %t && %env_asan_opts=detect_stack_use_after_return=1 not %run %t 2>&1 | FileCheck %s
3 // RUN: %clangxx_asan  -O2 %s -pthread -o %t && %env_asan_opts=detect_stack_use_after_return=1 not %run %t 2>&1 | FileCheck %s
4 // RUN: %clangxx_asan  -O3 %s -pthread -o %t && %env_asan_opts=detect_stack_use_after_return=1 not %run %t 2>&1 | FileCheck %s
5 // RUN: %env_asan_opts=detect_stack_use_after_return=0 %run %t
6 // RUN: %clangxx_asan  -O0 %s -pthread -o %t -fsanitize-address-use-after-return=always && not %run %t 2>&1 | FileCheck %s
7 // RUN: %clangxx_asan  -O1 %s -pthread -o %t -fsanitize-address-use-after-return=always && not %run %t 2>&1 | FileCheck %s
8 // RUN: %clangxx_asan  -O2 %s -pthread -o %t -fsanitize-address-use-after-return=always && not %run %t 2>&1 | FileCheck %s
9 // RUN: %clangxx_asan  -O3 %s -pthread -o %t -fsanitize-address-use-after-return=always && not %run %t 2>&1 | FileCheck %s
10 // RUN: %clangxx_asan  -O3 %s -pthread -o %t -fsanitize-address-use-after-return=never && %run %t
11 // Regression test for a CHECK failure with small stack size and large frame.
12 // RUN: %clangxx_asan  -O3 %s -pthread -o %t -DkSize=10000 -DUseThread -DkStackSize=131072 && %env_asan_opts=detect_stack_use_after_return=1 not %run %t 2>&1 | FileCheck --check-prefix=THREAD %s
13 // RUN: %clangxx_asan  -O3 %s -pthread -o %t -DkSize=10000 -DUseThread -DkStackSize=131072 -fsanitize-address-use-after-return=always && not %run %t 2>&1 | FileCheck --check-prefix=THREAD %s
14 //
15 // Test that we can find UAR in a thread other than main (UAR mode: runtime):
16 // RUN: %clangxx_asan  -DUseThread -O2 %s -pthread -o %t && %env_asan_opts=detect_stack_use_after_return=1 not %run %t 2>&1 | FileCheck --check-prefix=THREAD %s
17 //
18 // Test the max_uar_stack_size_log/min_uar_stack_size_log flag.
19 // (uses the previous)
20 //
21 // RUN: %env_asan_opts=detect_stack_use_after_return=1:max_uar_stack_size_log=20:verbosity=1 not %run %t 2>&1 | FileCheck --check-prefix=CHECK-20 %s
22 // RUN: %env_asan_opts=detect_stack_use_after_return=1:min_uar_stack_size_log=24:max_uar_stack_size_log=24:verbosity=1 not %run %t 2>&1 | FileCheck --check-prefix=CHECK-24 %s
23 //
24 // Test that we can find UAR in a thread other than main (UAR mode: always):
25 // RUN: %clangxx_asan  -DUseThread -O2 %s -pthread -o %t -fsanitize-address-use-after-return=always && not %run %t 2>&1 | FileCheck --check-prefix=THREAD %s
26 //
27 // Test the max_uar_stack_size_log/min_uar_stack_size_log flag.
28 // (uses the previous)
29 //
30 // RUN: %env_asan_opts=max_uar_stack_size_log=20:verbosity=1 not %run %t 2>&1 | FileCheck --check-prefix=CHECK-20 %s
31 // RUN: %env_asan_opts=min_uar_stack_size_log=24:max_uar_stack_size_log=24:verbosity=1 not %run %t 2>&1 | FileCheck --check-prefix=CHECK-24 %s
32 
33 // This test runs out of stack on AArch64.
34 // UNSUPPORTED: target=aarch64{{.*}}
35 // stack size log lower than expected
36 // XFAIL: target={{.*(freebsd|netbsd).*}}
37 
38 // FIXME: Fix this test for dynamic runtime on arm linux.
39 // UNSUPPORTED: (arm-linux || armhf-linux) && asan-dynamic-runtime
40 
41 #include <limits.h>
42 #include <pthread.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 
46 #ifndef kSize
47 # define kSize 1
48 #endif
49 
50 #ifndef UseThread
51 # define UseThread 0
52 #endif
53 
54 #ifndef kStackSize
55 # define kStackSize 0
56 #endif
57 
58 __attribute__((noinline))
Ident(char * x)59 char *Ident(char *x) {
60   fprintf(stderr, "1: %p\n", x);
61   return x;
62 }
63 
64 __attribute__((noinline))
Func1()65 char *Func1() {
66   char local[kSize];
67   return Ident(local);
68 }
69 
70 __attribute__((noinline))
Func2(char * x)71 void Func2(char *x) {
72   fprintf(stderr, "2: %p\n", x);
73   *x = 1;
74   // CHECK: WRITE of size 1 {{.*}} thread T0
75   // CHECK:     #0{{.*}}Func2{{.*}}stack-use-after-return.cpp:[[@LINE-2]]
76   // CHECK: is located in stack of thread T0 at offset
77   // CHECK: 'local'{{.*}} <== Memory access at offset {{16|32}} is inside this variable
78   // THREAD: WRITE of size 1 {{.*}} thread T{{[1-9]}}
79   // THREAD:     #0{{.*}}Func2{{.*}}stack-use-after-return.cpp:[[@LINE-6]]
80   // THREAD: is located in stack of thread T{{[1-9]}} at offset
81   // THREAD: 'local'{{.*}} <== Memory access at offset {{16|32}} is inside this variable
82   // CHECK-20: T0: FakeStack created:{{.*}} stack_size_log: 20
83   // CHECK-24: T0: FakeStack created:{{.*}} stack_size_log: 24
84 }
85 
Thread(void * unused)86 void *Thread(void *unused)  {
87   Func2(Func1());
88   return NULL;
89 }
90 
main(int argc,char ** argv)91 int main(int argc, char **argv) {
92 #if UseThread
93   pthread_attr_t attr;
94   pthread_attr_init(&attr);
95   if (kStackSize > 0) {
96     size_t desired_stack_size = kStackSize;
97 #ifdef PTHREAD_STACK_MIN
98     if (desired_stack_size < PTHREAD_STACK_MIN) {
99       desired_stack_size = PTHREAD_STACK_MIN;
100     }
101 #endif
102 
103     int ret = pthread_attr_setstacksize(&attr, desired_stack_size);
104     if (ret != 0) {
105       fprintf(stderr, "pthread_attr_setstacksize returned %d\n", ret);
106       abort();
107     }
108 
109     size_t stacksize_check;
110     ret = pthread_attr_getstacksize(&attr, &stacksize_check);
111     if (ret != 0) {
112       fprintf(stderr, "pthread_attr_getstacksize returned %d\n", ret);
113       abort();
114     }
115 
116     if (stacksize_check != desired_stack_size) {
117       fprintf(stderr, "Unable to set stack size to %d, the stack size is %d.\n",
118               (int)desired_stack_size, (int)stacksize_check);
119       abort();
120     }
121   }
122   pthread_t t;
123   pthread_create(&t, &attr, Thread, 0);
124   pthread_attr_destroy(&attr);
125   pthread_join(t, 0);
126 #else
127   Func2(Func1());
128 #endif
129   return 0;
130 }
131