diff --git a/compiler-rt/lib/asan/asan_interceptors.cpp b/compiler-rt/lib/asan/asan_interceptors.cpp --- a/compiler-rt/lib/asan/asan_interceptors.cpp +++ b/compiler-rt/lib/asan/asan_interceptors.cpp @@ -248,8 +248,7 @@ uptr bottom = stack & ~(PageSize - 1); ssize += stack - bottom; ssize = RoundUpTo(ssize, PageSize); - static const uptr kMaxSaneContextStackSize = 1 << 22; // 4 Mb - if (AddrIsInMem(bottom) && ssize && ssize <= kMaxSaneContextStackSize) { + if (AddrIsInMem(bottom) && ssize) { PoisonShadow(bottom, ssize, 0); } } diff --git a/compiler-rt/test/asan/TestCases/Linux/swapcontext_annotation.cpp b/compiler-rt/test/asan/TestCases/Linux/swapcontext_annotation.cpp --- a/compiler-rt/test/asan/TestCases/Linux/swapcontext_annotation.cpp +++ b/compiler-rt/test/asan/TestCases/Linux/swapcontext_annotation.cpp @@ -32,6 +32,8 @@ char *next_child_stack; const int kStackSize = 1 << 20; +// There used to be a limitation for stack unpoisoning (size <= 4Mb), check that it's gone. +const int kHugeStackSize = 1 << 23; const void *main_thread_stack; size_t main_thread_stacksize; @@ -47,7 +49,8 @@ // Simulate __asan_handle_no_return(). __attribute__((noinline)) void CallNoReturn() { jmp_buf env; - if (setjmp(env) != 0) return; + if (setjmp(env) != 0) + return; LongJump(env); _exit(1); @@ -59,13 +62,12 @@ printf("NextChild from: %p %zu\n", from_stack, from_stacksize); - char x[32] = {0}; // Stack gets poisoned. + char x[32] = {0}; // Stack gets poisoned. printf("NextChild: %p\n", x); CallNoReturn(); - __sanitizer_start_switch_fiber(nullptr, - main_thread_stack, + __sanitizer_start_switch_fiber(nullptr, main_thread_stack, main_thread_stacksize); CallNoReturn(); if (swapcontext(&next_child_context, &orig_context) < 0) { @@ -76,10 +78,9 @@ void Child(int mode) { CallNoReturn(); - __sanitizer_finish_switch_fiber(nullptr, - &main_thread_stack, + __sanitizer_finish_switch_fiber(nullptr, &main_thread_stack, &main_thread_stacksize); - char x[32] = {0}; // Stack gets poisoned. + char x[32] = {0}; // Stack gets poisoned. printf("Child: %p\n", x); CallNoReturn(); // (a) Do nothing, just return to parent function. @@ -87,13 +88,11 @@ // something. // (c) Jump to another function which will then jump back to the main function if (mode == 0) { - __sanitizer_start_switch_fiber(nullptr, - main_thread_stack, + __sanitizer_start_switch_fiber(nullptr, main_thread_stack, main_thread_stacksize); CallNoReturn(); } else if (mode == 1) { - __sanitizer_start_switch_fiber(nullptr, - main_thread_stack, + __sanitizer_start_switch_fiber(nullptr, main_thread_stack, main_thread_stacksize); CallNoReturn(); if (swapcontext(&child_context, &orig_context) < 0) { @@ -107,8 +106,7 @@ next_child_context.uc_stack.ss_sp = next_child_stack; next_child_context.uc_stack.ss_size = kStackSize / 2; makecontext(&next_child_context, (void (*)())NextChild, 0); - __sanitizer_start_switch_fiber(nullptr, - next_child_context.uc_stack.ss_sp, + __sanitizer_start_switch_fiber(nullptr, next_child_context.uc_stack.ss_sp, next_child_context.uc_stack.ss_size); CallNoReturn(); if (swapcontext(&child_context, &next_child_context) < 0) { @@ -129,9 +127,8 @@ } makecontext(&child_context, (void (*)())Child, 1, mode); CallNoReturn(); - void* fake_stack_save; - __sanitizer_start_switch_fiber(&fake_stack_save, - child_context.uc_stack.ss_sp, + void *fake_stack_save; + __sanitizer_start_switch_fiber(&fake_stack_save, child_context.uc_stack.ss_sp, child_context.uc_stack.ss_size); CallNoReturn(); if (swapcontext(&orig_context, &child_context) < 0) { @@ -139,8 +136,7 @@ _exit(1); } CallNoReturn(); - __sanitizer_finish_switch_fiber(fake_stack_save, - &from_stack, + __sanitizer_finish_switch_fiber(fake_stack_save, &from_stack, &from_stacksize); CallNoReturn(); printf("Main context from: %p %zu\n", from_stack, from_stacksize); @@ -152,9 +148,58 @@ return child_stack[arg]; } +ucontext_t orig_huge_stack_context; +ucontext_t child_huge_stack_context; + +void ChildHugeStack() { + __sanitizer_finish_switch_fiber(nullptr, &main_thread_stack, + &main_thread_stacksize); + char x[32] = {0}; // Stack gets poisoned. + __sanitizer_start_switch_fiber(nullptr, main_thread_stack, + main_thread_stacksize); + if (swapcontext(&child_huge_stack_context, &orig_huge_stack_context) < 0) { + perror("swapcontext"); + _exit(1); + } +} + +void DoRunHugeStack(char *child_stack) { + getcontext(&child_huge_stack_context); + child_huge_stack_context.uc_stack.ss_sp = child_stack; + child_huge_stack_context.uc_stack.ss_size = kHugeStackSize; + makecontext(&child_huge_stack_context, (void (*)())ChildHugeStack, 0); + void *fake_stack_save; + __sanitizer_start_switch_fiber(&fake_stack_save, + child_huge_stack_context.uc_stack.ss_sp, + child_huge_stack_context.uc_stack.ss_size); + if (swapcontext(&orig_huge_stack_context, &child_huge_stack_context) < 0) { + perror("swapcontext"); + _exit(1); + } + __sanitizer_finish_switch_fiber( + fake_stack_save, (const void **)&child_huge_stack_context.uc_stack.ss_sp, + &child_huge_stack_context.uc_stack.ss_size); + for (int i = 0; i < kHugeStackSize; ++i) { + child_stack[i] = i; + } +} + +void RunHugeStack() { + const int run_offset = 1 << 14; + char *heap = new char[kHugeStackSize + run_offset + 1]; + DoRunHugeStack(heap); + DoRunHugeStack(heap + run_offset); + DoRunHugeStack(heap); + delete[] heap; +} + void handler(int sig) { CallNoReturn(); } int main(int argc, char **argv) { + // CHECK: WARNING: ASan doesn't fully support makecontext/swapcontext + // CHECK-NOT: ASan is ignoring requested __asan_handle_no_return + RunHugeStack(); + // set up a signal that will spam and trigger __asan_handle_no_return at // tricky moments struct sigaction act = {}; @@ -176,7 +221,6 @@ char *heap = new char[kStackSize + 1]; next_child_stack = new char[kStackSize + 1]; char stack[kStackSize + 1]; - // CHECK: WARNING: ASan doesn't fully support makecontext/swapcontext int ret = 0; // CHECK-NOT: ASan is ignoring requested __asan_handle_no_return for (unsigned int i = 0; i < 30; ++i) {