CCTLib
Calling-context and data-object attribution library for Intel Pin
exc_dtor_cleanup.cpp
Go to the documentation of this file.
1 // Destructor called during unwind. Each Guard object writes to buf in its
2 // destructor while an exception propagates. Verifies cctlib's callback
3 // ordering plays nicely with per-frame cleanup code, which itself contains
4 // memory writes deadspy/redspy/loadspy must track.
5 //
6 // dtorcleanup_try_marker (in-try before the throw) and
7 // dtorcleanup_catch_marker (in-catch(int)) are asserted to be direct
8 // children of main -- the cleanup-landing-pad path must not misplace
9 // the catch body under __cxa_throw.
10 #include <cstdint>
11 #include <cstdio>
12 #define ITERS 500
13 static volatile uint64_t sink;
14 static uint64_t buf[ITERS];
15 
16 extern "C" __attribute__((noinline)) void dtorcleanup_try_marker(int i) {
17  __asm__ __volatile__("" ::: "memory"); sink ^= (uint64_t)i;
18 }
19 extern "C" __attribute__((noinline)) void dtorcleanup_catch_marker(int i) {
20  __asm__ __volatile__("" ::: "memory"); sink ^= (uint64_t)i << 8;
21 }
22 
23 struct Guard {
24  uint64_t* slot;
25  uint64_t v;
26  Guard(uint64_t* s, uint64_t v_) : slot(s), v(v_) { *slot = v; }
27  // noexcept: an exception from a destructor called during unwind would
28  // call std::terminate, which would defeat the point of this test.
29  ~Guard() noexcept { *slot ^= 0x00FF00FF00FF00FFULL; }
30 };
31 
32 static void thrower(int i) {
33  Guard g1(&buf[i], 0x1010);
34  {
35  Guard g2(&buf[i], 0x2020);
36  throw i; // both guards' destructors run during unwind
37  }
38 }
39 
40 int main(int argc, char** argv) {
41  (void)argc; (void)argv;
42  int caught = 0;
43  for (int i = 0; i < ITERS; ++i) {
44  try {
45  dtorcleanup_try_marker(i);
46  thrower(i);
47  } catch (int v) {
48  dtorcleanup_catch_marker(i);
49  caught += v == i;
50  buf[i] ^= 0xCC;
51  }
52  }
53  for (int i = 0; i < ITERS; ++i) sink ^= buf[i];
54  fprintf(stderr, "exc_dtor_cleanup: caught=%d iters=%d sink=%llx\n",
55  caught, ITERS, (unsigned long long)sink);
56  return caught == ITERS ? 0 : 1;
57 }
#define ITERS
int main(int argc, char **argv)
static uint64_t buf[ITERS]
static void thrower(int i)
static volatile uint64_t sink
__attribute__((noinline)) void dtorcleanup_try_marker(int i)
uint64_t v
Guard(uint64_t *s, uint64_t v_)
~Guard() noexcept
uint64_t * slot