1 // Test ASan detection of stack-overflow condition.
2
3 // RUN: %clangxx_asan -O0 %s -DSMALL_FRAME -pthread -o %t && env ASAN_OPTIONS=use_sigaltstack=1 not %run %t 2>&1 | FileCheck %s
4 // RUN: %clangxx_asan -O3 %s -DSMALL_FRAME -pthread -o %t && env ASAN_OPTIONS=use_sigaltstack=1 not %run %t 2>&1 | FileCheck %s
5 // RUN: %clangxx_asan -O0 %s -DSAVE_ALL_THE_REGISTERS -pthread -o %t && env ASAN_OPTIONS=use_sigaltstack=1 not %run %t 2>&1 | FileCheck %s
6 // RUN: %clangxx_asan -O3 %s -DSAVE_ALL_THE_REGISTERS -pthread -o %t && env ASAN_OPTIONS=use_sigaltstack=1 not %run %t 2>&1 | FileCheck %s
7 // RUN: %clangxx_asan -O0 %s -pthread -o %t && env ASAN_OPTIONS=use_sigaltstack=1 not %run %t 2>&1 | FileCheck %s
8 // RUN: %clangxx_asan -O3 %s -pthread -o %t && env ASAN_OPTIONS=use_sigaltstack=1 not %run %t 2>&1 | FileCheck %s
9
10 // RUN: %clangxx_asan -O0 %s -DTHREAD -DSMALL_FRAME -pthread -o %t && env ASAN_OPTIONS=use_sigaltstack=1 not %run %t 2>&1 | FileCheck %s
11 // RUN: %clangxx_asan -O3 %s -DTHREAD -DSMALL_FRAME -pthread -o %t && env ASAN_OPTIONS=use_sigaltstack=1 not %run %t 2>&1 | FileCheck %s
12 // RUN: %clangxx_asan -O0 %s -DTHREAD -DSAVE_ALL_THE_REGISTERS -pthread -o %t && env ASAN_OPTIONS=use_sigaltstack=1 not %run %t 2>&1 | FileCheck %s
13 // RUN: %clangxx_asan -O3 %s -DTHREAD -DSAVE_ALL_THE_REGISTERS -pthread -o %t && env ASAN_OPTIONS=use_sigaltstack=1 not %run %t 2>&1 | FileCheck %s
14 // RUN: %clangxx_asan -O0 %s -DTHREAD -pthread -o %t && env ASAN_OPTIONS=use_sigaltstack=1 not %run %t 2>&1 | FileCheck %s
15 // RUN: %clangxx_asan -O3 %s -DTHREAD -pthread -o %t && env ASAN_OPTIONS=use_sigaltstack=1 not %run %t 2>&1 | FileCheck %s
16 // RUN: not %run %t 2>&1 | FileCheck %s
17 // REQUIRES: stable-runtime
18
19 #include <assert.h>
20 #include <stdlib.h>
21 #include <pthread.h>
22 #include <unistd.h>
23 #include <sys/time.h>
24 #include <sys/resource.h>
25
26 const int BS = 1024;
27 volatile char x;
28 volatile int y = 1;
29 volatile int z0, z1, z2, z3, z4, z5, z6, z7, z8, z9, z10, z11, z12, z13;
30
recursive_func(char * p)31 void recursive_func(char *p) {
32 #if defined(SMALL_FRAME)
33 char *buf = 0;
34 #elif defined(SAVE_ALL_THE_REGISTERS)
35 char *buf = 0;
36 int t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13;
37 t0 = z0;
38 t1 = z1;
39 t2 = z2;
40 t3 = z3;
41 t4 = z4;
42 t5 = z5;
43 t6 = z6;
44 t7 = z7;
45 t8 = z8;
46 t9 = z9;
47 t10 = z10;
48 t11 = z11;
49 t12 = z12;
50 t13 = z13;
51
52 z0 = t0;
53 z1 = t1;
54 z2 = t2;
55 z3 = t3;
56 z4 = t4;
57 z5 = t5;
58 z6 = t6;
59 z7 = t7;
60 z8 = t8;
61 z9 = t9;
62 z10 = t10;
63 z11 = t11;
64 z12 = t12;
65 z13 = t13;
66 #else
67 char buf[BS];
68 if (p)
69 assert(p - buf >= BS);
70 buf[rand() % BS] = 1;
71 buf[rand() % BS] = 2;
72 x = buf[rand() % BS];
73 #endif
74 if (y)
75 recursive_func(buf);
76 x = 1; // prevent tail call optimization
77 // CHECK: {{stack-overflow on address 0x.* \(pc 0x.* sp 0x.* bp 0x.* T.*\)}}
78 // If stack overflow happens during function prologue, stack trace may be
79 // corrupted. Unwind tables are not always 100% exact there.
80 // For this reason, we don't do any further checks.
81 }
82
ThreadFn(void * unused)83 void *ThreadFn(void* unused) {
84 recursive_func(0);
85 return 0;
86 }
87
LimitStackAndReexec(int argc,char ** argv)88 void LimitStackAndReexec(int argc, char **argv) {
89 struct rlimit rlim;
90 int res = getrlimit(RLIMIT_STACK, &rlim);
91 assert(res == 0);
92 if (rlim.rlim_cur == RLIM_INFINITY) {
93 rlim.rlim_cur = 128 * 1024;
94 res = setrlimit(RLIMIT_STACK, &rlim);
95 assert(res == 0);
96
97 execv(argv[0], argv);
98 assert(0 && "unreachable");
99 }
100 }
101
main(int argc,char ** argv)102 int main(int argc, char **argv) {
103 LimitStackAndReexec(argc, argv);
104 #ifdef THREAD
105 pthread_t t;
106 pthread_create(&t, 0, ThreadFn, 0);
107 pthread_join(t, 0);
108 #else
109 recursive_func(0);
110 #endif
111 return 0;
112 }
113