Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 1 | // Test ASan detection of stack-overflow condition when Linux sends SIGBUS. |
| 2 | |
Pirama Arumuga Nainar | 799172d | 2016-03-03 15:50:30 -0800 | [diff] [blame^] | 3 | // RUN: %clangxx_asan -O0 %s -o %t && %env_asan_opts=use_sigaltstack=1 not %run %t 2>&1 | FileCheck %s |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 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(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, &rlim); |
| 31 | assert(res == 0); |
| 32 | if (rlim.rlim_cur == RLIM_INFINITY) { |
| 33 | rlim.rlim_cur = 256 * 1024; |
| 34 | res = setrlimit(RLIMIT_STACK, &rlim); |
| 35 | assert(res == 0); |
| 36 | |
| 37 | execv(argv[0], 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("/proc/self/maps", "r"); |
| 51 | char a[1000]; |
| 52 | void *p = 0; |
| 53 | while (fgets(a, sizeof a, f)) { |
| 54 | if (strstr(a, "[stack]")) { |
| 55 | unsigned long addr; |
| 56 | if (sscanf(a, "%lx", &addr) == 1) |
| 57 | p = mmap((void *)(addr - 4 * pagesize), pagesize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); |
| 58 | } |
| 59 | } |
| 60 | assert(p); |
| 61 | |
| 62 | recursive_func(0); |
| 63 | return 0; |
| 64 | } |