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