[compiler-rt] r282582 - [ASAN] Pass previous stack information through __sanitizer_finish_switch_fiber

Dmitry Vyukov via llvm-commits llvm-commits at lists.llvm.org
Wed Sep 28 05:28:17 PDT 2016


Author: dvyukov
Date: Wed Sep 28 07:28:16 2016
New Revision: 282582

URL: http://llvm.org/viewvc/llvm-project?rev=282582&view=rev
Log:
[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


Modified:
    compiler-rt/trunk/include/sanitizer/common_interface_defs.h
    compiler-rt/trunk/lib/asan/asan_thread.cc
    compiler-rt/trunk/lib/asan/asan_thread.h
    compiler-rt/trunk/test/asan/TestCases/Linux/swapcontext_annotation.cc

Modified: compiler-rt/trunk/include/sanitizer/common_interface_defs.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/include/sanitizer/common_interface_defs.h?rev=282582&r1=282581&r2=282582&view=diff
==============================================================================
--- compiler-rt/trunk/include/sanitizer/common_interface_defs.h (original)
+++ compiler-rt/trunk/include/sanitizer/common_interface_defs.h Wed Sep 28 07:28:16 2016
@@ -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

Modified: compiler-rt/trunk/lib/asan/asan_thread.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_thread.cc?rev=282582&r1=282581&r2=282582&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_thread.cc (original)
+++ compiler-rt/trunk/lib/asan/asan_thread.cc Wed Sep 28 07:28:16 2016
@@ -141,7 +141,9 @@ void AsanThread::StartSwitchFiber(FakeSt
     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(FakeS
     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
 }
 
 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);
 }
 }

Modified: compiler-rt/trunk/lib/asan/asan_thread.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_thread.h?rev=282582&r1=282581&r2=282582&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_thread.h (original)
+++ compiler-rt/trunk/lib/asan/asan_thread.h Wed Sep 28 07:28:16 2016
@@ -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) &&

Modified: compiler-rt/trunk/test/asan/TestCases/Linux/swapcontext_annotation.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/asan/TestCases/Linux/swapcontext_annotation.cc?rev=282582&r1=282581&r2=282582&view=diff
==============================================================================
--- compiler-rt/trunk/test/asan/TestCases/Linux/swapcontext_annotation.cc (original)
+++ compiler-rt/trunk/test/asan/TestCases/Linux/swapcontext_annotation.cc Wed Sep 28 07:28:16 2016
@@ -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 CallNoRet
 
 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_s
   }
   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_s
     _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_s
 
 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");
 




More information about the llvm-commits mailing list