123caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell// Check that ASan plays well with easy cases of makecontext/swapcontext. 223caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell 323caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell// RUN: %clangxx_asan -O0 %s -o %t && %run %t 2>&1 | FileCheck %s 422144ab7552f0799bcfca506bf4ffa7f70a06649Gareth Hughes// RUN: %clangxx_asan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s 523caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell// RUN: %clangxx_asan -O2 %s -o %t && %run %t 2>&1 | FileCheck %s 622144ab7552f0799bcfca506bf4ffa7f70a06649Gareth Hughes// RUN: %clangxx_asan -O3 %s -o %t && %run %t 2>&1 | FileCheck %s 723caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell// 823caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell// This test is too sublte to try on non-x86 arch for now. 923caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell// REQUIRES: x86_64-supported-target,i386-supported-target 1023caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell 1123caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell#include <stdio.h> 1223caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell#include <ucontext.h> 1323caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell#include <unistd.h> 1423caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell 1523caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwellucontext_t orig_context; 1623caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwellucontext_t child_context; 1723caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell 1823caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwellconst int kStackSize = 1 << 20; 1923caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell 2023caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell__attribute__((noinline)) 2123caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwellvoid Throw() { 2223caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell throw 1; 2323caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell} 2423caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell 2523caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell__attribute__((noinline)) 2623caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwellvoid ThrowAndCatch() { 2723caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell try { 2823caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell Throw(); 2923caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell } catch(int a) { 3023caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell printf("ThrowAndCatch: %d\n", a); 3123caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell } 3223caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell} 3323caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell 3423caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwellvoid Child(int mode) { 3523caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell char x[32] = {0}; // Stack gets poisoned. 3623caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell printf("Child: %p\n", x); 3723caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell ThrowAndCatch(); // Simulate __asan_handle_no_return(). 3823caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell // (a) Do nothing, just return to parent function. 3923caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell // (b) Jump into the original function. Stack remains poisoned unless we do 4023caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell // something. 4123caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell if (mode == 1) { 4223caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell if (swapcontext(&child_context, &orig_context) < 0) { 4323caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell perror("swapcontext"); 4423caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell _exit(0); 4523caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell } 4623caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell } 4723caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell} 4823caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell 4923caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwellint Run(int arg, int mode, char *child_stack) { 5023caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell printf("Child stack: %p\n", child_stack); 5123caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell // Setup child context. 5223caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell getcontext(&child_context); 5323caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell child_context.uc_stack.ss_sp = child_stack; 5423caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell child_context.uc_stack.ss_size = kStackSize / 2; 5523caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell if (mode == 0) { 5623caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell child_context.uc_link = &orig_context; 5723caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell } 5823caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell makecontext(&child_context, (void (*)())Child, 1, mode); 5923caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell if (swapcontext(&orig_context, &child_context) < 0) { 6023caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell perror("swapcontext"); 6123caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell return 0; 6223caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell } 6323caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell // Touch childs's stack to make sure it's unpoisoned. 6423caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell for (int i = 0; i < kStackSize; i++) { 6523caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell child_stack[i] = i; 6623caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell } 675e23af22f708a66695c0e44e599c26f02d8d4dcdGareth Hughes return child_stack[arg]; 685e23af22f708a66695c0e44e599c26f02d8d4dcdGareth Hughes} 695e23af22f708a66695c0e44e599c26f02d8d4dcdGareth Hughes 705e23af22f708a66695c0e44e599c26f02d8d4dcdGareth Hughesint main(int argc, char **argv) { 715e23af22f708a66695c0e44e599c26f02d8d4dcdGareth Hughes char stack[kStackSize + 1]; 725e23af22f708a66695c0e44e599c26f02d8d4dcdGareth Hughes // CHECK: WARNING: ASan doesn't fully support makecontext/swapcontext 7323caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell int ret = 0; 7423caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell ret += Run(argc - 1, 0, stack); 7523caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell printf("Test1 passed\n"); 765e23af22f708a66695c0e44e599c26f02d8d4dcdGareth Hughes // CHECK: Test1 passed 7723caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell ret += Run(argc - 1, 1, stack); 7823caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell printf("Test2 passed\n"); 7923caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell // CHECK: Test2 passed 8023caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell char *heap = new char[kStackSize + 1]; 8123caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell ret += Run(argc - 1, 0, heap); 8223caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell printf("Test3 passed\n"); 8323caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell // CHECK: Test3 passed 8423caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell ret += Run(argc - 1, 1, heap); 8523caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell printf("Test4 passed\n"); 8623caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell // CHECK: Test4 passed 8723caf20169ac38436ee9c13914f1d6aa7cf6bb5eKeith Whitwell 885e23af22f708a66695c0e44e599c26f02d8d4dcdGareth Hughes delete [] heap; 895e23af22f708a66695c0e44e599c26f02d8d4dcdGareth Hughes return ret; 905e23af22f708a66695c0e44e599c26f02d8d4dcdGareth Hughes} 915e23af22f708a66695c0e44e599c26f02d8d4dcdGareth Hughes