Home | History | Annotate | Download | only in Linux
      1 // Check that ASan plays well with easy cases of makecontext/swapcontext.
      2 
      3 // RUN: %clangxx_asan -O0 %s -o %t && %run %t 2>&1 | FileCheck %s
      4 // RUN: %clangxx_asan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
      5 // RUN: %clangxx_asan -O2 %s -o %t && %run %t 2>&1 | FileCheck %s
      6 // RUN: %clangxx_asan -O3 %s -o %t && %run %t 2>&1 | FileCheck %s
      7 //
      8 // This test is too sublte to try on non-x86 arch for now.
      9 // REQUIRES: x86-target-arch
     10 
     11 #include <stdio.h>
     12 #include <ucontext.h>
     13 #include <unistd.h>
     14 
     15 ucontext_t orig_context;
     16 ucontext_t child_context;
     17 
     18 const int kStackSize = 1 << 20;
     19 
     20 __attribute__((noinline))
     21 void Throw() {
     22   throw 1;
     23 }
     24 
     25 __attribute__((noinline))
     26 void ThrowAndCatch() {
     27   try {
     28     Throw();
     29   } catch(int a) {
     30     printf("ThrowAndCatch: %d\n", a);
     31   }
     32 }
     33 
     34 void Child(int mode) {
     35   char x[32] = {0};  // Stack gets poisoned.
     36   printf("Child: %p\n", x);
     37   ThrowAndCatch();  // Simulate __asan_handle_no_return().
     38   // (a) Do nothing, just return to parent function.
     39   // (b) Jump into the original function. Stack remains poisoned unless we do
     40   //     something.
     41   if (mode == 1) {
     42     if (swapcontext(&child_context, &orig_context) < 0) {
     43       perror("swapcontext");
     44       _exit(0);
     45     }
     46   }
     47 }
     48 
     49 int Run(int arg, int mode, char *child_stack) {
     50   printf("Child stack: %p\n", child_stack);
     51   // Setup child context.
     52   getcontext(&child_context);
     53   child_context.uc_stack.ss_sp = child_stack;
     54   child_context.uc_stack.ss_size = kStackSize / 2;
     55   if (mode == 0) {
     56     child_context.uc_link = &orig_context;
     57   }
     58   makecontext(&child_context, (void (*)())Child, 1, mode);
     59   if (swapcontext(&orig_context, &child_context) < 0) {
     60     perror("swapcontext");
     61     return 0;
     62   }
     63   // Touch childs's stack to make sure it's unpoisoned.
     64   for (int i = 0; i < kStackSize; i++) {
     65     child_stack[i] = i;
     66   }
     67   return child_stack[arg];
     68 }
     69 
     70 int main(int argc, char **argv) {
     71   char stack[kStackSize + 1];
     72   // CHECK: WARNING: ASan doesn't fully support makecontext/swapcontext
     73   int ret = 0;
     74   ret += Run(argc - 1, 0, stack);
     75   printf("Test1 passed\n");
     76   // CHECK: Test1 passed
     77   ret += Run(argc - 1, 1, stack);
     78   printf("Test2 passed\n");
     79   // CHECK: Test2 passed
     80   char *heap = new char[kStackSize + 1];
     81   ret += Run(argc - 1, 0, heap);
     82   printf("Test3 passed\n");
     83   // CHECK: Test3 passed
     84   ret += Run(argc - 1, 1, heap);
     85   printf("Test4 passed\n");
     86   // CHECK: Test4 passed
     87 
     88   delete [] heap;
     89   return ret;
     90 }
     91