1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
|
// RUN: %clangxx_asan -O0 -pthread %s -o %t && %env_asan_opts=use_sigaltstack=0 not --crash %run %t 2>&1 | FileCheck %s
// Check that fake stack does not discard frames on the main stack, when GC is
// triggered from high alt stack.
#include <algorithm>
#include <assert.h>
#include <csignal>
#include <cstdint>
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
const size_t kStackSize = 0x100000;
int *on_thread;
int *p;
template <size_t N> void Fn() {
int t[N];
p = t;
if constexpr (N > 1)
Fn<N - 1>();
}
static void Handler(int signo) {
fprintf(stderr, "Handler Frame:%p\n", __builtin_frame_address(0));
// Trigger GC and create a lot of frame to reuse "Thread" frame if it was
// discarded.
for (int i = 0; i < 1000; ++i)
Fn<1000>();
// If we discarder and reused "Thread" frame, the next line will crash with
// false report.
*on_thread = 10;
fprintf(stderr, "SUCCESS\n");
// CHECK: SUCCESS
}
void *Thread(void *arg) {
fprintf(stderr, "Thread Frame:%p\n", __builtin_frame_address(0));
stack_t stack = {
.ss_sp = arg,
.ss_flags = 0,
.ss_size = kStackSize,
};
assert(sigaltstack(&stack, nullptr) == 0);
struct sigaction sa = {};
sa.sa_handler = Handler;
sa.sa_flags = SA_ONSTACK;
sigaction(SIGABRT, &sa, nullptr);
// Store pointer to the local var, so we can access this frame from the signal
// handler when the frame is still alive.
int n;
on_thread = &n;
// Abort should schedule FakeStack GC and call handler on alt stack.
abort();
}
int main(void) {
// Allocate main and alt stack for future thread.
void *main_stack;
void *alt_stack;
size_t const kPageSize = sysconf(_SC_PAGESIZE);
assert(posix_memalign(&main_stack, kPageSize, kStackSize) == 0);
assert(posix_memalign(&alt_stack, kPageSize, kStackSize) == 0);
// Pick the lower stack as the main stack, as we want to trigger GC in
// FakeStack from alt stack in a such way that main stack is allocated below.
if ((uintptr_t)main_stack > (uintptr_t)alt_stack)
std::swap(alt_stack, main_stack);
pthread_attr_t attr;
assert(pthread_attr_init(&attr) == 0);
assert(pthread_attr_setstack(&attr, main_stack, kStackSize) == 0);
fprintf(stderr, "main_stack: %p-%p\n", main_stack,
(char *)main_stack + kStackSize);
fprintf(stderr, "alt_stack: %p-%p\n", alt_stack,
(char *)alt_stack + kStackSize);
pthread_t tid;
assert(pthread_create(&tid, &attr, Thread, alt_stack) == 0);
pthread_join(tid, nullptr);
free(main_stack);
free(alt_stack);
return 0;
}
|