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_64-supported-target,i386-supported-target
10
11#include <stdio.h>
12#include <ucontext.h>
13#include <unistd.h>
14
15ucontext_t orig_context;
16ucontext_t child_context;
17
18const int kStackSize = 1 << 20;
19
20__attribute__((noinline))
21void Throw() {
22  throw 1;
23}
24
25__attribute__((noinline))
26void ThrowAndCatch() {
27  try {
28    Throw();
29  } catch(int a) {
30    printf("ThrowAndCatch: %d\n", a);
31  }
32}
33
34void 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
49int 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
70int 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