10870028410087e67a0049c76cb7c64f02c260d24Alexey Samsonov// Check that ASan plays well with easy cases of makecontext/swapcontext. 20870028410087e67a0049c76cb7c64f02c260d24Alexey Samsonov 32d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines// RUN: %clangxx_asan -O0 %s -o %t && %run %t 2>&1 | FileCheck %s 42d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines// RUN: %clangxx_asan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s 52d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines// RUN: %clangxx_asan -O2 %s -o %t && %run %t 2>&1 | FileCheck %s 62d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines// RUN: %clangxx_asan -O3 %s -o %t && %run %t 2>&1 | FileCheck %s 730e970f769ccf11e61e472c6f8b22f8e866c592fKostya Serebryany// 830e970f769ccf11e61e472c6f8b22f8e866c592fKostya Serebryany// This test is too sublte to try on non-x86 arch for now. 930e970f769ccf11e61e472c6f8b22f8e866c592fKostya Serebryany// REQUIRES: x86_64-supported-target,i386-supported-target 100870028410087e67a0049c76cb7c64f02c260d24Alexey Samsonov 110870028410087e67a0049c76cb7c64f02c260d24Alexey Samsonov#include <stdio.h> 120870028410087e67a0049c76cb7c64f02c260d24Alexey Samsonov#include <ucontext.h> 130870028410087e67a0049c76cb7c64f02c260d24Alexey Samsonov#include <unistd.h> 140870028410087e67a0049c76cb7c64f02c260d24Alexey Samsonov 150870028410087e67a0049c76cb7c64f02c260d24Alexey Samsonovucontext_t orig_context; 160870028410087e67a0049c76cb7c64f02c260d24Alexey Samsonovucontext_t child_context; 170870028410087e67a0049c76cb7c64f02c260d24Alexey Samsonov 1830e970f769ccf11e61e472c6f8b22f8e866c592fKostya Serebryanyconst int kStackSize = 1 << 20; 1930e970f769ccf11e61e472c6f8b22f8e866c592fKostya Serebryany 2030e970f769ccf11e61e472c6f8b22f8e866c592fKostya Serebryany__attribute__((noinline)) 2130e970f769ccf11e61e472c6f8b22f8e866c592fKostya Serebryanyvoid Throw() { 2230e970f769ccf11e61e472c6f8b22f8e866c592fKostya Serebryany throw 1; 2330e970f769ccf11e61e472c6f8b22f8e866c592fKostya Serebryany} 2430e970f769ccf11e61e472c6f8b22f8e866c592fKostya Serebryany 2530e970f769ccf11e61e472c6f8b22f8e866c592fKostya Serebryany__attribute__((noinline)) 2630e970f769ccf11e61e472c6f8b22f8e866c592fKostya Serebryanyvoid ThrowAndCatch() { 2730e970f769ccf11e61e472c6f8b22f8e866c592fKostya Serebryany try { 2830e970f769ccf11e61e472c6f8b22f8e866c592fKostya Serebryany Throw(); 2930e970f769ccf11e61e472c6f8b22f8e866c592fKostya Serebryany } catch(int a) { 3030e970f769ccf11e61e472c6f8b22f8e866c592fKostya Serebryany printf("ThrowAndCatch: %d\n", a); 3130e970f769ccf11e61e472c6f8b22f8e866c592fKostya Serebryany } 3230e970f769ccf11e61e472c6f8b22f8e866c592fKostya Serebryany} 3330e970f769ccf11e61e472c6f8b22f8e866c592fKostya Serebryany 340870028410087e67a0049c76cb7c64f02c260d24Alexey Samsonovvoid Child(int mode) { 350870028410087e67a0049c76cb7c64f02c260d24Alexey Samsonov char x[32] = {0}; // Stack gets poisoned. 360870028410087e67a0049c76cb7c64f02c260d24Alexey Samsonov printf("Child: %p\n", x); 3730e970f769ccf11e61e472c6f8b22f8e866c592fKostya Serebryany ThrowAndCatch(); // Simulate __asan_handle_no_return(). 380870028410087e67a0049c76cb7c64f02c260d24Alexey Samsonov // (a) Do nothing, just return to parent function. 390870028410087e67a0049c76cb7c64f02c260d24Alexey Samsonov // (b) Jump into the original function. Stack remains poisoned unless we do 400870028410087e67a0049c76cb7c64f02c260d24Alexey Samsonov // something. 410870028410087e67a0049c76cb7c64f02c260d24Alexey Samsonov if (mode == 1) { 420870028410087e67a0049c76cb7c64f02c260d24Alexey Samsonov if (swapcontext(&child_context, &orig_context) < 0) { 430870028410087e67a0049c76cb7c64f02c260d24Alexey Samsonov perror("swapcontext"); 440870028410087e67a0049c76cb7c64f02c260d24Alexey Samsonov _exit(0); 450870028410087e67a0049c76cb7c64f02c260d24Alexey Samsonov } 460870028410087e67a0049c76cb7c64f02c260d24Alexey Samsonov } 470870028410087e67a0049c76cb7c64f02c260d24Alexey Samsonov} 480870028410087e67a0049c76cb7c64f02c260d24Alexey Samsonov 4930e970f769ccf11e61e472c6f8b22f8e866c592fKostya Serebryanyint Run(int arg, int mode, char *child_stack) { 500870028410087e67a0049c76cb7c64f02c260d24Alexey Samsonov printf("Child stack: %p\n", child_stack); 510870028410087e67a0049c76cb7c64f02c260d24Alexey Samsonov // Setup child context. 520870028410087e67a0049c76cb7c64f02c260d24Alexey Samsonov getcontext(&child_context); 530870028410087e67a0049c76cb7c64f02c260d24Alexey Samsonov child_context.uc_stack.ss_sp = child_stack; 540870028410087e67a0049c76cb7c64f02c260d24Alexey Samsonov child_context.uc_stack.ss_size = kStackSize / 2; 550870028410087e67a0049c76cb7c64f02c260d24Alexey Samsonov if (mode == 0) { 560870028410087e67a0049c76cb7c64f02c260d24Alexey Samsonov child_context.uc_link = &orig_context; 570870028410087e67a0049c76cb7c64f02c260d24Alexey Samsonov } 580870028410087e67a0049c76cb7c64f02c260d24Alexey Samsonov makecontext(&child_context, (void (*)())Child, 1, mode); 590870028410087e67a0049c76cb7c64f02c260d24Alexey Samsonov if (swapcontext(&orig_context, &child_context) < 0) { 600870028410087e67a0049c76cb7c64f02c260d24Alexey Samsonov perror("swapcontext"); 610870028410087e67a0049c76cb7c64f02c260d24Alexey Samsonov return 0; 620870028410087e67a0049c76cb7c64f02c260d24Alexey Samsonov } 630870028410087e67a0049c76cb7c64f02c260d24Alexey Samsonov // Touch childs's stack to make sure it's unpoisoned. 640870028410087e67a0049c76cb7c64f02c260d24Alexey Samsonov for (int i = 0; i < kStackSize; i++) { 650870028410087e67a0049c76cb7c64f02c260d24Alexey Samsonov child_stack[i] = i; 660870028410087e67a0049c76cb7c64f02c260d24Alexey Samsonov } 670870028410087e67a0049c76cb7c64f02c260d24Alexey Samsonov return child_stack[arg]; 680870028410087e67a0049c76cb7c64f02c260d24Alexey Samsonov} 690870028410087e67a0049c76cb7c64f02c260d24Alexey Samsonov 700870028410087e67a0049c76cb7c64f02c260d24Alexey Samsonovint main(int argc, char **argv) { 7130e970f769ccf11e61e472c6f8b22f8e866c592fKostya Serebryany char stack[kStackSize + 1]; 720870028410087e67a0049c76cb7c64f02c260d24Alexey Samsonov // CHECK: WARNING: ASan doesn't fully support makecontext/swapcontext 730870028410087e67a0049c76cb7c64f02c260d24Alexey Samsonov int ret = 0; 7430e970f769ccf11e61e472c6f8b22f8e866c592fKostya Serebryany ret += Run(argc - 1, 0, stack); 750870028410087e67a0049c76cb7c64f02c260d24Alexey Samsonov printf("Test1 passed\n"); 760870028410087e67a0049c76cb7c64f02c260d24Alexey Samsonov // CHECK: Test1 passed 7730e970f769ccf11e61e472c6f8b22f8e866c592fKostya Serebryany ret += Run(argc - 1, 1, stack); 780870028410087e67a0049c76cb7c64f02c260d24Alexey Samsonov printf("Test2 passed\n"); 790870028410087e67a0049c76cb7c64f02c260d24Alexey Samsonov // CHECK: Test2 passed 8030e970f769ccf11e61e472c6f8b22f8e866c592fKostya Serebryany char *heap = new char[kStackSize + 1]; 8130e970f769ccf11e61e472c6f8b22f8e866c592fKostya Serebryany ret += Run(argc - 1, 0, heap); 8230e970f769ccf11e61e472c6f8b22f8e866c592fKostya Serebryany printf("Test3 passed\n"); 8330e970f769ccf11e61e472c6f8b22f8e866c592fKostya Serebryany // CHECK: Test3 passed 8430e970f769ccf11e61e472c6f8b22f8e866c592fKostya Serebryany ret += Run(argc - 1, 1, heap); 8530e970f769ccf11e61e472c6f8b22f8e866c592fKostya Serebryany printf("Test4 passed\n"); 8630e970f769ccf11e61e472c6f8b22f8e866c592fKostya Serebryany // CHECK: Test4 passed 8730e970f769ccf11e61e472c6f8b22f8e866c592fKostya Serebryany 8830e970f769ccf11e61e472c6f8b22f8e866c592fKostya Serebryany delete [] heap; 890870028410087e67a0049c76cb7c64f02c260d24Alexey Samsonov return ret; 900870028410087e67a0049c76cb7c64f02c260d24Alexey Samsonov} 91