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 // Android and musl do not support swapcontext. 10 // REQUIRES: x86-target-arch && glibc-2.27 11 12 #include <assert.h> 13 #include <memory.h> 14 #include <stdio.h> 15 #include <ucontext.h> 16 #include <unistd.h> 17 18 ucontext_t orig_context; 19 ucontext_t child_context; 20 21 const int kStackSize = 1 << 20; 22 23 __attribute__((noinline)) 24 void Throw() { 25 throw 1; 26 } 27 28 __attribute__((noinline)) 29 void ThrowAndCatch() { 30 try { 31 Throw(); 32 } catch(int a) { 33 printf("ThrowAndCatch: %d\n", a); 34 } 35 } 36 37 void Child(int mode) { 38 assert(orig_context.uc_stack.ss_size == 0); 39 char x[32] = {0}; // Stack gets poisoned. 40 printf("Child: %p\n", x); 41 ThrowAndCatch(); // Simulate __asan_handle_no_return(). 42 // (a) Do nothing, just return to parent function. 43 // (b) Jump into the original function. Stack remains poisoned unless we do 44 // something. 45 if (mode == 1) { 46 if (swapcontext(&child_context, &orig_context) < 0) { 47 perror("swapcontext"); 48 _exit(0); 49 } 50 } 51 } 52 53 int Run(int arg, int mode, char *child_stack) { 54 printf("Child stack: %p\n", child_stack); 55 // Setup child context. 56 memset(&child_context, 0xff, sizeof(child_context)); 57 getcontext(&child_context); 58 assert(child_context.uc_stack.ss_size == 0); 59 child_context.uc_stack.ss_sp = child_stack; 60 child_context.uc_stack.ss_size = kStackSize / 2; 61 if (mode == 0) { 62 child_context.uc_link = &orig_context; 63 } 64 makecontext(&child_context, (void (*)())Child, 1, mode); 65 memset(&orig_context, 0xff, sizeof(orig_context)); 66 if (swapcontext(&orig_context, &child_context) < 0) { 67 perror("swapcontext"); 68 return 0; 69 } 70 // Touch childs's stack to make sure it's unpoisoned. 71 for (int i = 0; i < kStackSize; i++) { 72 child_stack[i] = i; 73 } 74 return child_stack[arg]; 75 } 76 77 int main(int argc, char **argv) { 78 char stack[kStackSize + 1]; 79 // CHECK: WARNING: ASan doesn't fully support makecontext/swapcontext 80 int ret = 0; 81 ret += Run(argc - 1, 0, stack); 82 printf("Test1 passed\n"); 83 // CHECK: Test1 passed 84 ret += Run(argc - 1, 1, stack); 85 printf("Test2 passed\n"); 86 // CHECK: Test2 passed 87 char *heap = new char[kStackSize + 1]; 88 ret += Run(argc - 1, 0, heap); 89 printf("Test3 passed\n"); 90 // CHECK: Test3 passed 91 ret += Run(argc - 1, 1, heap); 92 printf("Test4 passed\n"); 93 // CHECK: Test4 passed 94 95 delete [] heap; 96 return ret; 97 } 98