File: fake_stack_gc.cpp

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (96 lines) | stat: -rw-r--r-- 2,609 bytes parent folder | download
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;
}