| 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 | |