1 | // Test ASan detection of stack-overflow condition when Linux sends SIGBUS. |
2 | |
3 | // RUN: %clangxx_asan -O0 %s -o %t && %env_asan_opts=use_sigaltstack=1 not %run %t 2>&1 | FileCheck %s |
4 | |
5 | #include <assert.h> |
6 | #include <stdio.h> |
7 | #include <stdlib.h> |
8 | #include <string.h> |
9 | #include <unistd.h> |
10 | #include <sys/mman.h> |
11 | #include <sys/resource.h> |
12 | |
13 | const int BS = 1024; |
14 | volatile char x; |
15 | volatile int y = 1; |
16 | |
17 | void recursive_func(char *p) { |
18 | char buf[BS]; |
19 | buf[rand() % BS] = 1; |
20 | buf[rand() % BS] = 2; |
21 | x = buf[rand() % BS]; |
22 | if (y) |
23 | recursive_func(p: buf); |
24 | x = 1; // prevent tail call optimization |
25 | // CHECK: {{stack-overflow on address 0x.* \(pc 0x.* bp 0x.* sp 0x.* T.*\)}} |
26 | } |
27 | |
28 | void LimitStackAndReexec(int argc, char **argv) { |
29 | struct rlimit rlim; |
30 | int res = getrlimit(RLIMIT_STACK, rlimits: &rlim); |
31 | assert(res == 0); |
32 | if (rlim.rlim_cur == RLIM_INFINITY) { |
33 | rlim.rlim_cur = 256 * 1024; |
34 | res = setrlimit(RLIMIT_STACK, rlimits: &rlim); |
35 | assert(res == 0); |
36 | |
37 | execv(path: argv[0], argv: argv); |
38 | assert(0 && "unreachable" ); |
39 | } |
40 | } |
41 | |
42 | int main(int argc, char **argv) { |
43 | LimitStackAndReexec(argc, argv); |
44 | |
45 | // Map some memory just before the start of the current stack vma. |
46 | // When the stack grows down and crashes into it, Linux can send |
47 | // SIGBUS instead of SIGSEGV. See: |
48 | // http://lkml.iu.edu/hypermail/linux/kernel/1008.1/02299.html |
49 | const long pagesize = sysconf(_SC_PAGESIZE); |
50 | FILE *f = fopen(filename: "/proc/self/maps" , modes: "r" ); |
51 | char a[1000]; |
52 | void *p = 0; |
53 | while (fgets(s: a, n: sizeof a, stream: f)) { |
54 | if (strstr(haystack: a, needle: "[stack]" )) { |
55 | unsigned long addr; |
56 | if (sscanf(s: a, format: "%lx" , &addr) == 1) |
57 | p = mmap(addr: (void *)(addr - 4 * pagesize), len: pagesize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, fd: -1, offset: 0); |
58 | } |
59 | } |
60 | assert(p); |
61 | |
62 | recursive_func(p: 0); |
63 | return 0; |
64 | } |
65 | |