Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / compiler-rt / test / asan / TestCases / Linux / swapcontext_test.cpp
blobd9381bd7ded685bb0ceac3e014207d7aff0984ef
1 // Check that ASan plays well with easy cases of makecontext/swapcontext.
3 // RUN: %clangxx_asan -O0 %s -o %t && %run %t
4 // RUN: %clangxx_asan -O3 %s -o %t && %run %t
5 // RUN: %clangxx_asan -fsanitize-address-use-after-return=never -O0 %s -o %t && %run %t
6 // RUN: %clangxx_asan -fsanitize-address-use-after-return=never -O3 %s -o %t && %run %t
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
12 #include <assert.h>
13 #include <memory.h>
14 #include <stdio.h>
15 #include <ucontext.h>
16 #include <unistd.h>
18 ucontext_t orig_context;
19 ucontext_t child_context;
21 const int kStackSize = 1 << 20;
23 __attribute__((noinline)) void Throw() { throw 1; }
25 __attribute__((noinline)) void ThrowAndCatch() {
26 try {
27 Throw();
28 } catch (int a) {
29 printf("ThrowAndCatch: %d\n", a);
33 void Child(int mode, int a, int b, int c) {
34 char x[32] = {0}; // Stack gets poisoned.
35 printf("Child: %d\n", x);
36 assert(a == 'a');
37 assert(b == 'b');
38 assert(c == 'c');
39 ThrowAndCatch(); // Simulate __asan_handle_no_return().
40 // (a) Do nothing, just return to parent function.
41 // (b) Jump into the original function. Stack remains poisoned unless we do
42 // something.
43 if (mode == 1) {
44 if (swapcontext(&child_context, &orig_context) < 0) {
45 perror("swapcontext");
46 _exit(0);
51 int Run(int arg, int mode, char *child_stack) {
52 printf("Child stack: %p\n", child_stack);
53 // Setup child context.
54 getcontext(&child_context);
55 child_context.uc_stack.ss_sp = child_stack;
56 child_context.uc_stack.ss_size = kStackSize / 2;
57 if (mode == 0) {
58 child_context.uc_link = &orig_context;
60 makecontext(&child_context, (void (*)())Child, 4, mode, 'a', 'b', 'c');
61 if (swapcontext(&orig_context, &child_context) < 0) {
62 perror("swapcontext");
63 return 0;
65 // Touch childs's stack to make sure it's unpoisoned.
66 for (int i = 0; i < kStackSize; i++) {
67 child_stack[i] = i;
69 return child_stack[arg];
72 ucontext_t poll_context;
73 ucontext_t poller_context;
75 void Poll() {
76 swapcontext(&poll_context, &poller_context);
79 char x = 0;
80 printf("POLL: %p\n", &x);
83 swapcontext(&poll_context, &poller_context);
86 void DoRunPoll(char *poll_stack) {
87 getcontext(&poll_context);
88 poll_context.uc_stack.ss_sp = poll_stack;
89 poll_context.uc_stack.ss_size = kStackSize / 2;
90 makecontext(&poll_context, Poll, 0);
92 getcontext(&poller_context);
94 swapcontext(&poller_context, &poll_context);
95 swapcontext(&poller_context, &poll_context);
97 // Touch poll's stack to make sure it's unpoisoned.
98 for (int i = 0; i < kStackSize; i++) {
99 poll_stack[i] = i;
103 void RunPoll() {
104 char *poll_stack = new char[kStackSize];
106 for (size_t i = 0; i < 2; ++i) {
107 DoRunPoll(poll_stack);
110 delete[] poll_stack;
113 int main(int argc, char **argv) {
114 char stack[kStackSize + 1];
115 int ret = 0;
116 ret += Run(argc - 1, 0, stack);
117 ret += Run(argc - 1, 1, stack);
118 char *heap = new char[kStackSize + 1];
119 ret += Run(argc - 1, 0, heap);
120 ret += Run(argc - 1, 1, heap);
122 RunPoll();
123 delete[] heap;
124 return ret;