diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2016-09-28 12:28:16 +0000 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2016-09-28 12:28:16 +0000 |
| commit | b3587836bca51ea61af5a0c685c55d4b7a51450d (patch) | |
| tree | 335dc10efc06d02156d9e49501bb844de9cc5068 | |
| parent | b107a22afbd2a5a07259c56b7ce84450fe7c8783 (diff) | |
| download | bcm5719-llvm-b3587836bca51ea61af5a0c685c55d4b7a51450d.tar.gz bcm5719-llvm-b3587836bca51ea61af5a0c685c55d4b7a51450d.zip | |
[ASAN] Pass previous stack information through __sanitizer_finish_switch_fiber
This patch extends __sanitizer_finish_switch_fiber method to optionally return previous stack base and size.
This solves the problem of coroutines/fibers library not knowing the original stack context from which the library is used. It's incorrect to assume that such context is always the default stack of current thread (e.g. one such library may be used from a fiber/coroutine created by another library). Bulding a separate stack tracking mechanism would not only duplicate AsanThread, but also require each coroutines/fibers library to integrate with it.
Author: Andrii Grynenko (andriigrynenko)
Reviewed in: https://reviews.llvm.org/D24628
llvm-svn: 282582
| -rw-r--r-- | compiler-rt/include/sanitizer/common_interface_defs.h | 4 | ||||
| -rw-r--r-- | compiler-rt/lib/asan/asan_thread.cc | 16 | ||||
| -rw-r--r-- | compiler-rt/lib/asan/asan_thread.h | 3 | ||||
| -rw-r--r-- | compiler-rt/test/asan/TestCases/Linux/swapcontext_annotation.cc | 74 |
4 files changed, 68 insertions, 29 deletions
diff --git a/compiler-rt/include/sanitizer/common_interface_defs.h b/compiler-rt/include/sanitizer/common_interface_defs.h index d8ff272c29f..130f0f27af5 100644 --- a/compiler-rt/include/sanitizer/common_interface_defs.h +++ b/compiler-rt/include/sanitizer/common_interface_defs.h @@ -179,7 +179,9 @@ extern "C" { // use-after-return detection. void __sanitizer_start_switch_fiber(void **fake_stack_save, const void *bottom, size_t size); - void __sanitizer_finish_switch_fiber(void *fake_stack_save); + void __sanitizer_finish_switch_fiber(void *fake_stack_save, + const void **bottom_old, + size_t *size_old); #ifdef __cplusplus } // extern "C" #endif diff --git a/compiler-rt/lib/asan/asan_thread.cc b/compiler-rt/lib/asan/asan_thread.cc index 14684086b3e..537b53d9e0c 100644 --- a/compiler-rt/lib/asan/asan_thread.cc +++ b/compiler-rt/lib/asan/asan_thread.cc @@ -141,7 +141,9 @@ void AsanThread::StartSwitchFiber(FakeStack **fake_stack_save, uptr bottom, current_fake_stack->Destroy(this->tid()); } -void AsanThread::FinishSwitchFiber(FakeStack *fake_stack_save) { +void AsanThread::FinishSwitchFiber(FakeStack *fake_stack_save, + uptr *bottom_old, + uptr *size_old) { if (!atomic_load(&stack_switching_, memory_order_relaxed)) { Report("ERROR: finishing a fiber switch that has not started\n"); Die(); @@ -152,6 +154,10 @@ void AsanThread::FinishSwitchFiber(FakeStack *fake_stack_save) { fake_stack_ = fake_stack_save; } + if (bottom_old) + *bottom_old = stack_bottom_; + if (size_old) + *size_old = stack_top_ - stack_bottom_; stack_bottom_ = next_stack_bottom_; stack_top_ = next_stack_top_; atomic_store(&stack_switching_, 0, memory_order_release); @@ -447,12 +453,16 @@ void __sanitizer_start_switch_fiber(void **fakestacksave, const void *bottom, } SANITIZER_INTERFACE_ATTRIBUTE -void __sanitizer_finish_switch_fiber(void* fakestack) { +void __sanitizer_finish_switch_fiber(void* fakestack, + const void **bottom_old, + uptr *size_old) { AsanThread *t = GetCurrentThread(); if (!t) { VReport(1, "__asan_finish_switch_fiber called from unknown thread\n"); return; } - t->FinishSwitchFiber((FakeStack*)fakestack); + t->FinishSwitchFiber((FakeStack*)fakestack, + (uptr*)bottom_old, + (uptr*)size_old); } } diff --git a/compiler-rt/lib/asan/asan_thread.h b/compiler-rt/lib/asan/asan_thread.h index 92a92a2e863..f53dfb71244 100644 --- a/compiler-rt/lib/asan/asan_thread.h +++ b/compiler-rt/lib/asan/asan_thread.h @@ -94,7 +94,8 @@ class AsanThread { } void StartSwitchFiber(FakeStack **fake_stack_save, uptr bottom, uptr size); - void FinishSwitchFiber(FakeStack *fake_stack_save); + void FinishSwitchFiber(FakeStack *fake_stack_save, uptr *bottom_old, + uptr *size_old); bool has_fake_stack() { return !atomic_load(&stack_switching_, memory_order_relaxed) && diff --git a/compiler-rt/test/asan/TestCases/Linux/swapcontext_annotation.cc b/compiler-rt/test/asan/TestCases/Linux/swapcontext_annotation.cc index 90aabaee205..56e811942b8 100644 --- a/compiler-rt/test/asan/TestCases/Linux/swapcontext_annotation.cc +++ b/compiler-rt/test/asan/TestCases/Linux/swapcontext_annotation.cc @@ -1,12 +1,17 @@ // Check that ASan plays well with annotated makecontext/swapcontext. -// RUN: %clangxx_asan -lpthread -O0 %s -o %t && %run %t 2>&1 | FileCheck %s -// RUN: %clangxx_asan -lpthread -O1 %s -o %t && %run %t 2>&1 | FileCheck %s -// RUN: %clangxx_asan -lpthread -O2 %s -o %t && %run %t 2>&1 | FileCheck %s -// RUN: %clangxx_asan -lpthread -O3 %s -o %t && %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -std=c++11 -lpthread -O0 %s -o %t && %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -std=c++11 -lpthread -O1 %s -o %t && %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -std=c++11 -lpthread -O2 %s -o %t && %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -std=c++11 -lpthread -O3 %s -o %t && %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -std=c++11 -lpthread -O0 %s -o %t && %run %t 2>&1 | FileCheck <( seq 60 | xargs -i -- grep LOOPCHECK %s ) --check-prefix LOOPCHECK +// RUN: %clangxx_asan -std=c++11 -lpthread -O1 %s -o %t && %run %t 2>&1 | FileCheck <( seq 60 | xargs -i -- grep LOOPCHECK %s ) --check-prefix LOOPCHECK +// RUN: %clangxx_asan -std=c++11 -lpthread -O2 %s -o %t && %run %t 2>&1 | FileCheck <( seq 60 | xargs -i -- grep LOOPCHECK %s ) --check-prefix LOOPCHECK +// RUN: %clangxx_asan -std=c++11 -lpthread -O3 %s -o %t && %run %t 2>&1 | FileCheck <( seq 60 | xargs -i -- grep LOOPCHECK %s ) --check-prefix LOOPCHECK + // // This test is too subtle to try on non-x86 arch for now. -// REQUIRES: x86_64-supported-target,i386-supported-target +// REQUIRES: x86-target-arch #include <pthread.h> #include <setjmp.h> @@ -25,9 +30,12 @@ char *next_child_stack; const int kStackSize = 1 << 20; -void *main_thread_stack; +const void *main_thread_stack; size_t main_thread_stacksize; +const void *from_stack; +size_t from_stacksize; + __attribute__((noinline, noreturn)) void LongJump(jmp_buf env) { longjmp(env, 1); _exit(1); @@ -44,14 +52,18 @@ __attribute__((noinline)) void CallNoReturn() { void NextChild() { CallNoReturn(); - __sanitizer_finish_switch_fiber(); + __sanitizer_finish_switch_fiber(nullptr, &from_stack, &from_stacksize); + + printf("NextChild from: %p %zu\n", from_stack, from_stacksize); char x[32] = {0}; // Stack gets poisoned. printf("NextChild: %p\n", x); CallNoReturn(); - __sanitizer_start_switch_fiber(main_thread_stack, main_thread_stacksize); + __sanitizer_start_switch_fiber(nullptr, + main_thread_stack, + main_thread_stacksize); CallNoReturn(); if (swapcontext(&next_child_context, &orig_context) < 0) { perror("swapcontext"); @@ -61,7 +73,9 @@ void NextChild() { void Child(int mode) { CallNoReturn(); - __sanitizer_finish_switch_fiber(); + __sanitizer_finish_switch_fiber(nullptr, + &main_thread_stack, + &main_thread_stacksize); char x[32] = {0}; // Stack gets poisoned. printf("Child: %p\n", x); CallNoReturn(); @@ -70,21 +84,28 @@ void Child(int mode) { // something. // (c) Jump to another function which will then jump back to the main function if (mode == 0) { - __sanitizer_start_switch_fiber(main_thread_stack, main_thread_stacksize); + __sanitizer_start_switch_fiber(nullptr, + main_thread_stack, + main_thread_stacksize); CallNoReturn(); } else if (mode == 1) { - __sanitizer_start_switch_fiber(main_thread_stack, main_thread_stacksize); + __sanitizer_start_switch_fiber(nullptr, + main_thread_stack, + main_thread_stacksize); CallNoReturn(); if (swapcontext(&child_context, &orig_context) < 0) { perror("swapcontext"); _exit(1); } } else if (mode == 2) { + printf("NextChild stack: %p\n", next_child_stack); + getcontext(&next_child_context); 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(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) { @@ -105,7 +126,9 @@ int Run(int arg, int mode, char *child_stack) { } makecontext(&child_context, (void (*)())Child, 1, mode); CallNoReturn(); - __sanitizer_start_switch_fiber(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) { @@ -113,8 +136,11 @@ int Run(int arg, int mode, char *child_stack) { _exit(1); } CallNoReturn(); - __sanitizer_finish_switch_fiber(); + __sanitizer_finish_switch_fiber(fake_stack_save, + &from_stack, + &from_stacksize); CallNoReturn(); + printf("Main context from: %p %zu\n", from_stack, from_stacksize); // Touch childs's stack to make sure it's unpoisoned. for (int i = 0; i < kStackSize; i++) { @@ -125,17 +151,7 @@ int Run(int arg, int mode, char *child_stack) { void handler(int sig) { CallNoReturn(); } -void InitStackBounds() { - pthread_attr_t attr; - pthread_attr_init(&attr); - pthread_getattr_np(pthread_self(), &attr); - pthread_attr_getstack(&attr, &main_thread_stack, &main_thread_stacksize); - pthread_attr_destroy(&attr); -} - int main(int argc, char **argv) { - InitStackBounds(); - // set up a signal that will spam and trigger __asan_handle_no_return at // tricky moments struct sigaction act = {}; @@ -162,12 +178,22 @@ int main(int argc, char **argv) { // CHECK-NOT: ASan is ignoring requested __asan_handle_no_return for (unsigned int i = 0; i < 30; ++i) { ret += Run(argc - 1, 0, stack); + // LOOPCHECK: Child stack: [[CHILD_STACK:0x[0-9a-f]*]] + // LOOPCHECK: Main context from: [[CHILD_STACK]] 524288 ret += Run(argc - 1, 1, stack); + // LOOPCHECK: Child stack: [[CHILD_STACK:0x[0-9a-f]*]] + // LOOPCHECK: Main context from: [[CHILD_STACK]] 524288 ret += Run(argc - 1, 2, stack); + // LOOPCHECK: Child stack: [[CHILD_STACK:0x[0-9a-f]*]] + // LOOPCHECK: NextChild stack: [[NEXT_CHILD_STACK:0x[0-9a-f]*]] + // LOOPCHECK: NextChild from: [[CHILD_STACK]] 524288 + // LOOPCHECK: Main context from: [[NEXT_CHILD_STACK]] 524288 ret += Run(argc - 1, 0, heap); ret += Run(argc - 1, 1, heap); ret += Run(argc - 1, 2, heap); + printf("Iteration %d passed\n", i); } + // CHECK: Test passed printf("Test passed\n"); |

