[RISCV] Add RVVConstraint to SiFive custom matrix multiply instructions. (#124055)
[llvm-project.git] / compiler-rt / test / asan / TestCases / Posix / unpoison-alternate-stack.cpp
blob8e7d5082d0b5d9a87c7729819ee7bd8e620651b8
1 // Tests that __asan_handle_no_return properly unpoisons the signal alternate
2 // stack.
4 // Don't optimize, otherwise the variables which create redzones might be
5 // dropped.
6 // RUN: %clangxx_asan -fexceptions -O0 %s -o %t -pthread
7 // RUN: %env_asan_opts=detect_stack_use_after_return=0 %run %t
9 #include <algorithm>
10 #include <cassert>
11 #include <cerrno>
12 #include <csetjmp>
13 #include <cstdint>
14 #include <cstdio>
15 #include <cstdlib>
16 #include <cstring>
18 #include <limits.h>
19 #include <pthread.h>
20 #include <signal.h>
21 #include <sys/mman.h>
22 #include <unistd.h>
24 #include <sanitizer/asan_interface.h>
26 namespace {
28 struct TestContext {
29 char *LeftRedzone;
30 char *RightRedzone;
31 std::jmp_buf JmpBuf;
34 TestContext defaultStack;
35 TestContext signalStack;
37 // Create a new stack frame to ensure that logically, the stack frame should be
38 // unpoisoned when the function exits. Exit is performed via jump, not return,
39 // such that we trigger __asan_handle_no_return and not ordinary unpoisoning.
40 template <class Jump>
41 void __attribute__((noinline)) poisonStackAndJump(TestContext &c, Jump jump) {
42 char Blob[100]; // This variable must not be optimized out, because we use it
43 // to create redzones.
45 c.LeftRedzone = Blob - 1;
46 c.RightRedzone = Blob + sizeof(Blob);
48 assert(__asan_address_is_poisoned(c.LeftRedzone));
49 assert(__asan_address_is_poisoned(c.RightRedzone));
51 // Jump to avoid normal cleanup of redzone markers. Instead,
52 // __asan_handle_no_return is called which unpoisons the stacks.
53 jump();
56 void testOnCurrentStack() {
57 TestContext c;
59 if (0 == setjmp(c.JmpBuf))
60 poisonStackAndJump(c, [&] { longjmp(c.JmpBuf, 1); });
62 assert(0 == __asan_region_is_poisoned(c.LeftRedzone,
63 c.RightRedzone - c.LeftRedzone));
66 bool isOnSignalStack() {
67 stack_t Stack;
68 sigaltstack(nullptr, &Stack);
69 return Stack.ss_flags == SS_ONSTACK;
72 void signalHandler(int, siginfo_t *, void *) {
73 assert(isOnSignalStack());
75 // test on signal alternate stack
76 testOnCurrentStack();
78 // test unpoisoning when jumping between stacks
79 poisonStackAndJump(signalStack, [] { longjmp(defaultStack.JmpBuf, 1); });
82 void setSignalAlternateStack(void *AltStack) {
83 sigaltstack((stack_t const *)AltStack, nullptr);
85 struct sigaction Action = {};
86 Action.sa_sigaction = signalHandler;
87 Action.sa_flags = SA_SIGINFO | SA_NODEFER | SA_ONSTACK;
88 sigemptyset(&Action.sa_mask);
90 sigaction(SIGUSR1, &Action, nullptr);
93 // Main test function.
94 // Must be run on another thread to be able to control memory placement between
95 // default stack and alternate signal stack.
96 // If the alternate signal stack is placed in close proximity before the
97 // default stack, __asan_handle_no_return might unpoison both, even without
98 // being aware of the signal alternate stack.
99 // We want to test reliably that __asan_handle_no_return can properly unpoison
100 // the signal alternate stack.
101 void *threadFun(void *AltStack) {
102 // first test on default stack (sanity check), no signal alternate stack set
103 testOnCurrentStack();
105 setSignalAlternateStack(AltStack);
107 // test on default stack again, but now the signal alternate stack is set
108 testOnCurrentStack();
110 // set up jump to test unpoisoning when jumping between stacks
111 if (0 == setjmp(defaultStack.JmpBuf))
112 // Test on signal alternate stack, via signalHandler
113 poisonStackAndJump(defaultStack, [] { raise(SIGUSR1); });
115 assert(!isOnSignalStack());
117 assert(0 == __asan_region_is_poisoned(
118 defaultStack.LeftRedzone,
119 defaultStack.RightRedzone - defaultStack.LeftRedzone));
121 assert(0 == __asan_region_is_poisoned(
122 signalStack.LeftRedzone,
123 signalStack.RightRedzone - signalStack.LeftRedzone));
125 return nullptr;
128 } // namespace
130 // Check that __asan_handle_no_return properly unpoisons a signal alternate
131 // stack.
132 // __asan_handle_no_return tries to determine the stack boundaries and
133 // unpoisons all memory inside those. If this is not done properly, redzones for
134 // variables on can remain in shadow memory which might lead to false positive
135 // reports when the stack is reused.
136 int main() {
137 size_t const PageSize = sysconf(_SC_PAGESIZE);
138 // The Solaris defaults of 4k (32-bit) and 8k (64-bit) are too small.
139 size_t const MinStackSize = std::max<size_t>(PTHREAD_STACK_MIN, 16 * 1024);
140 // To align the alternate stack, we round this up to page_size.
141 size_t const DefaultStackSize =
142 (MinStackSize - 1 + PageSize) & ~(PageSize - 1);
143 // The alternate stack needs a certain size, or the signal handler segfaults.
144 size_t const AltStackSize = 10 * PageSize;
145 size_t const MappingSize = DefaultStackSize + AltStackSize;
146 // Using mmap guarantees proper alignment.
147 void *const Mapping = mmap(nullptr, MappingSize,
148 PROT_READ | PROT_WRITE,
149 MAP_PRIVATE | MAP_ANONYMOUS,
150 -1, 0);
152 stack_t AltStack = {};
153 AltStack.ss_sp = (char *)Mapping + DefaultStackSize;
154 AltStack.ss_flags = 0;
155 AltStack.ss_size = AltStackSize;
157 pthread_t Thread;
158 pthread_attr_t ThreadAttr;
159 pthread_attr_init(&ThreadAttr);
160 pthread_attr_setstack(&ThreadAttr, Mapping, DefaultStackSize);
161 pthread_create(&Thread, &ThreadAttr, &threadFun, (void *)&AltStack);
162 pthread_attr_destroy(&ThreadAttr);
164 pthread_join(Thread, nullptr);
166 munmap(Mapping, MappingSize);