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
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
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() {
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
);
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
44 if (swapcontext(&child_context
, &orig_context
) < 0) {
45 perror("swapcontext");
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;
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");
65 // Touch childs's stack to make sure it's unpoisoned.
66 for (int i
= 0; i
< kStackSize
; i
++) {
69 return child_stack
[arg
];
72 ucontext_t poll_context
;
73 ucontext_t poller_context
;
76 swapcontext(&poll_context
, &poller_context
);
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
++) {
104 char *poll_stack
= new char[kStackSize
];
106 for (size_t i
= 0; i
< 2; ++i
) {
107 DoRunPoll(poll_stack
);
113 int main(int argc
, char **argv
) {
114 char stack
[kStackSize
+ 1];
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
);