// Test ASan detection of stack-overflow condition. // RUN: %clangxx_asan -O0 %s -DSMALL_FRAME -pthread -o %t && %env_asan_opts=use_sigaltstack=1 not %run %t 2>&1 | FileCheck %s // RUN: %clangxx_asan -O3 %s -DSMALL_FRAME -pthread -o %t && %env_asan_opts=use_sigaltstack=1 not %run %t 2>&1 | FileCheck %s // RUN: %clangxx_asan -O0 %s -DSAVE_ALL_THE_REGISTERS -pthread -o %t && %env_asan_opts=use_sigaltstack=1 not %run %t 2>&1 | FileCheck %s // RUN: %clangxx_asan -O3 %s -DSAVE_ALL_THE_REGISTERS -pthread -o %t && %env_asan_opts=use_sigaltstack=1 not %run %t 2>&1 | FileCheck %s // RUN: %clangxx_asan -O0 %s -pthread -o %t && %env_asan_opts=use_sigaltstack=1 not %run %t 2>&1 | FileCheck %s // RUN: %clangxx_asan -O3 %s -pthread -o %t && %env_asan_opts=use_sigaltstack=1 not %run %t 2>&1 | FileCheck %s // RUN: %clangxx_asan -O0 %s -DTHREAD -DSMALL_FRAME -pthread -o %t && %env_asan_opts=use_sigaltstack=1 not %run %t 2>&1 | FileCheck %s // RUN: %clangxx_asan -O3 %s -DTHREAD -DSMALL_FRAME -pthread -o %t && %env_asan_opts=use_sigaltstack=1 not %run %t 2>&1 | FileCheck %s // RUN: %clangxx_asan -O0 %s -DTHREAD -DSAVE_ALL_THE_REGISTERS -pthread -o %t && %env_asan_opts=use_sigaltstack=1 not %run %t 2>&1 | FileCheck %s // RUN: %clangxx_asan -O3 %s -DTHREAD -DSAVE_ALL_THE_REGISTERS -pthread -o %t && %env_asan_opts=use_sigaltstack=1 not %run %t 2>&1 | FileCheck %s // RUN: %clangxx_asan -O0 %s -DTHREAD -pthread -o %t && %env_asan_opts=use_sigaltstack=1 not %run %t 2>&1 | FileCheck %s // RUN: %clangxx_asan -O3 %s -DTHREAD -pthread -o %t && %env_asan_opts=use_sigaltstack=1 not %run %t 2>&1 | FileCheck %s // RUN: not %run %t 2>&1 | FileCheck %s // REQUIRES: stable-runtime #include <assert.h> #include <stdlib.h> #include <pthread.h> #include <unistd.h> #include <sys/time.h> #include <sys/resource.h> #include <sanitizer/asan_interface.h> const int BS = 1024; volatile char x; volatile int y = 1; volatile int z0, z1, z2, z3, z4, z5, z6, z7, z8, z9, z10, z11, z12, z13; void recursive_func(char *p) { #if defined(SMALL_FRAME) char *buf = 0; #elif defined(SAVE_ALL_THE_REGISTERS) char *buf = 0; int t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13; t0 = z0; t1 = z1; t2 = z2; t3 = z3; t4 = z4; t5 = z5; t6 = z6; t7 = z7; t8 = z8; t9 = z9; t10 = z10; t11 = z11; t12 = z12; t13 = z13; z0 = t0; z1 = t1; z2 = t2; z3 = t3; z4 = t4; z5 = t5; z6 = t6; z7 = t7; z8 = t8; z9 = t9; z10 = t10; z11 = t11; z12 = t12; z13 = t13; #else char buf[BS]; // Check that the stack grows in the righ direction, unless we use fake stack. if (p && !__asan_get_current_fake_stack()) assert(p - buf >= BS); buf[rand() % BS] = 1; buf[rand() % BS] = 2; x = buf[rand() % BS]; #endif if (y) recursive_func(buf); x = 1; // prevent tail call optimization // CHECK: {{stack-overflow on address 0x.* \(pc 0x.* bp 0x.* sp 0x.* T.*\)}} // If stack overflow happens during function prologue, stack trace may be // corrupted. Unwind tables are not always 100% exact there. // For this reason, we don't do any further checks. } void *ThreadFn(void* unused) { recursive_func(0); return 0; } void LimitStackAndReexec(int argc, char **argv) { struct rlimit rlim; int res = getrlimit(RLIMIT_STACK, &rlim); assert(res == 0); if (rlim.rlim_cur == RLIM_INFINITY) { rlim.rlim_cur = 256 * 1024; res = setrlimit(RLIMIT_STACK, &rlim); assert(res == 0); execv(argv[0], argv); assert(0 && "unreachable"); } } int main(int argc, char **argv) { LimitStackAndReexec(argc, argv); #ifdef THREAD pthread_t t; pthread_create(&t, 0, ThreadFn, 0); pthread_join(t, 0); #else recursive_func(0); #endif return 0; }