Linux has 64k pages, so the old limit was only two pages. With ASLR the initial sp might be right at the start of the second page, so the stack will immediately grow down into the first page; and if you use all pages of a limited stack then asan hits a kernel bug to do with how stack guard pages are reported in /proc/self/maps: http://lkml.iu.edu//hypermail/linux/kernel/1501.0/01025.html We should still fix the underlying problems, but in the mean time this patch makes the test work with 64k pages as well as it does with 4k pages. llvm-svn: 225261
115 lines
3.6 KiB
C++
115 lines
3.6 KiB
C++
// Test ASan detection of stack-overflow condition.
|
|
|
|
// RUN: %clangxx_asan -O0 %s -DSMALL_FRAME -pthread -o %t && env ASAN_OPTIONS=use_sigaltstack=1 not %run %t 2>&1 | FileCheck %s
|
|
// RUN: %clangxx_asan -O3 %s -DSMALL_FRAME -pthread -o %t && env ASAN_OPTIONS=use_sigaltstack=1 not %run %t 2>&1 | FileCheck %s
|
|
// RUN: %clangxx_asan -O0 %s -DSAVE_ALL_THE_REGISTERS -pthread -o %t && env ASAN_OPTIONS=use_sigaltstack=1 not %run %t 2>&1 | FileCheck %s
|
|
// RUN: %clangxx_asan -O3 %s -DSAVE_ALL_THE_REGISTERS -pthread -o %t && env ASAN_OPTIONS=use_sigaltstack=1 not %run %t 2>&1 | FileCheck %s
|
|
// RUN: %clangxx_asan -O0 %s -pthread -o %t && env ASAN_OPTIONS=use_sigaltstack=1 not %run %t 2>&1 | FileCheck %s
|
|
// RUN: %clangxx_asan -O3 %s -pthread -o %t && env ASAN_OPTIONS=use_sigaltstack=1 not %run %t 2>&1 | FileCheck %s
|
|
|
|
// RUN: %clangxx_asan -O0 %s -DTHREAD -DSMALL_FRAME -pthread -o %t && env ASAN_OPTIONS=use_sigaltstack=1 not %run %t 2>&1 | FileCheck %s
|
|
// RUN: %clangxx_asan -O3 %s -DTHREAD -DSMALL_FRAME -pthread -o %t && env ASAN_OPTIONS=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_OPTIONS=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_OPTIONS=use_sigaltstack=1 not %run %t 2>&1 | FileCheck %s
|
|
// RUN: %clangxx_asan -O0 %s -DTHREAD -pthread -o %t && env ASAN_OPTIONS=use_sigaltstack=1 not %run %t 2>&1 | FileCheck %s
|
|
// RUN: %clangxx_asan -O3 %s -DTHREAD -pthread -o %t && env ASAN_OPTIONS=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;
|
|
}
|