CCTLib
Calling-context and data-object attribution library for Intel Pin
sig_sigsegv_recover.cpp
Go to the documentation of this file.
1 // SIGSEGV recovery via siglongjmp. Program deliberately dereferences NULL;
2 // SIGSEGV handler siglongjmp's back into main and the loop continues.
3 // This is a common pattern (JIT probes, GC page-fault trampolines).
4 // cctlib must handle the fault-plus-non-local-return without corrupting
5 // its trace-node state.
6 //
7 // sigsegv_try_marker (before poke) and sigsegv_recover_marker (post-
8 // siglongjmp on the sigsetjmp-returns-nonzero path) verify the signal-
9 // recovery re-anchor leaves the landing block as a direct child of main.
10 #include <cstdint>
11 #include <cstdio>
12 #include <csetjmp>
13 #include <csignal>
14 #include <cstring>
15 #define ITERS 200
16 static volatile uint64_t sink;
17 static uint64_t buf[ITERS];
18 static sigjmp_buf sjb;
19 
20 extern "C" __attribute__((noinline)) void sigsegv_try_marker(int i) {
21  __asm__ __volatile__("" ::: "memory"); sink ^= (uint64_t)i;
22 }
23 extern "C" __attribute__((noinline)) void sigsegv_recover_marker(int i) {
24  __asm__ __volatile__("" ::: "memory"); sink ^= (uint64_t)i << 8;
25 }
26 
27 static void handler(int) {
28  siglongjmp(sjb, 1);
29 }
30 
31 static void poke(int i) {
32  buf[i] = 0xC0;
33  // Force a real memory access to an unmapped page.
34  volatile int* bad = (volatile int*)(uintptr_t)0x1;
35  (void)*bad; // SIGSEGV -> handler -> siglongjmp
36  buf[i] = 0xC1; // never reached
37 }
38 
39 int main(int argc, char** argv) {
40  (void)argc; (void)argv;
41  struct sigaction sa;
42  memset(&sa, 0, sizeof(sa));
43  sa.sa_handler = handler;
44  sa.sa_flags = SA_NODEFER;
45  sigaction(SIGSEGV, &sa, nullptr);
46 
47  int recovered = 0;
48  for (int i = 0; i < ITERS; ++i) {
49  if (sigsetjmp(sjb, 1) == 0) {
50  sigsegv_try_marker(i);
51  poke(i);
52  } else {
53  sigsegv_recover_marker(i);
54  buf[i] ^= 0x0F;
55  ++recovered;
56  }
57  }
58  for (int i = 0; i < ITERS; ++i) sink ^= buf[i];
59  fprintf(stderr, "sig_sigsegv_recover: recovered=%d iters=%d sink=%llx\n",
60  recovered, ITERS, (unsigned long long)sink);
61  return recovered == ITERS ? 0 : 1;
62 }
#define ITERS
int main(int argc, char **argv)
static uint64_t buf[ITERS]
__attribute__((noinline)) void sigsegv_try_marker(int i)
static sigjmp_buf sjb
static void handler(int)
static volatile uint64_t sink
static void poke(int i)