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
26const int BS = 1024;
27volatile char x;
28volatile int y = 1;
29volatile int z0, z1, z2, z3, z4, z5, z6, z7, z8, z9, z10, z11, z12, z13;
30
31void 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
83void *ThreadFn(void* unused) {
84  recursive_func(0);
85  return 0;
86}
87
88void 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
102int 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