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