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