1 // RUN: %clangxx_msan -O0 %s -o %t && %run %t
2 
3 #include <assert.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <ucontext.h>
7 #include <unistd.h>
8 
9 #include <sanitizer/msan_interface.h>
10 
11 namespace {
12 
13 const int kStackSize = 1 << 20;
14 char fiber_stack[kStackSize] = {};
15 
16 ucontext_t main_ctx;
17 ucontext_t fiber_ctx;
18 
fiber()19 void fiber() {
20   printf("%s: entering fiber\n", __FUNCTION__);
21 
22   // This fiber was switched into from main. Verify the details of main's stack
23   // have been populated by MSAN.
24   const void *previous_stack_bottom = nullptr;
25   size_t previous_stack_size = 0;
26   __msan_finish_switch_fiber(&previous_stack_bottom, &previous_stack_size);
27   assert(previous_stack_bottom != nullptr);
28   assert(previous_stack_size != 0);
29 
30   printf("%s: implicitly swapcontext to main\n", __FUNCTION__);
31   __msan_start_switch_fiber(previous_stack_bottom, previous_stack_size);
32 }
33 
34 } // namespace
35 
36 // Set up a fiber, switch to it, and switch back, invoking __msan_*_switch_fiber
37 // functions along the way. At each step, validate the correct stack addresses and
38 // sizes are returned from those functions.
main(int argc,char ** argv)39 int main(int argc, char **argv) {
40   if (getcontext(&fiber_ctx) == -1) {
41     perror("getcontext");
42     _exit(1);
43   }
44   fiber_ctx.uc_stack.ss_sp = fiber_stack;
45   fiber_ctx.uc_stack.ss_size = sizeof(fiber_stack);
46   fiber_ctx.uc_link = &main_ctx;
47   makecontext(&fiber_ctx, fiber, 0);
48 
49   // Tell MSAN a fiber switch is about to occur, then perform the switch
50   printf("%s: swapcontext to fiber\n", __FUNCTION__);
51   __msan_start_switch_fiber(fiber_stack, kStackSize);
52   if (swapcontext(&main_ctx, &fiber_ctx) == -1) {
53     perror("swapcontext");
54     _exit(1);
55   }
56 
57   // The fiber switched to above now switched back here. Tell MSAN that switch
58   // is complete and verify the fiber details return by MSAN are correct.
59   const void *previous_stack_bottom = nullptr;
60   size_t previous_stack_size = 0;
61   __msan_finish_switch_fiber(&previous_stack_bottom, &previous_stack_size);
62   assert(previous_stack_bottom == fiber_stack);
63   assert(previous_stack_size == kStackSize);
64 
65   printf("%s: exiting\n", __FUNCTION__);
66 
67   return 0;
68 }
69