CCTLib
Calling-context and data-object attribution library for Intel Pin
exc_recurse_trycatch.cpp
Go to the documentation of this file.
1 // Try/catch INSIDE a recursive frame. Every recursive activation of
2 // `rec` wraps its downward call in try{...}catch(int){rethrow;}, so the
3 // throw at the deepest frame propagates through every frame's catch on
4 // its way out to main. Exercises marker anchoring while direct-self-
5 // recursion collapse is active: all `rec` activations share ONE
6 // TraceNode, so all four in-`rec` markers must appear as direct
7 // children of that single `rec` node, and never as descendants of
8 // __cxa_throw / _Unwind_*.
9 //
10 // Markers:
11 // rectry_try_marker called in the try body BEFORE the recursive
12 // call (fires on every entering frame; parent = rec)
13 // rectry_deep_marker called at depth==0 just before the throw
14 // (parent = rec)
15 // rectry_catch_marker called in the catch body BEFORE the rethrow
16 // (fires on every unwinding frame; parent = rec)
17 // rectry_after_marker called after the try (never reached in this
18 // test -- every path either throws or rethrows;
19 // we assert it does NOT appear as a leaf so a
20 // compiler that hoisted the call would be caught)
21 // rectry_outer_try in main's try body before recurse; parent = main
22 // rectry_outer_catch in main's catch body; parent = main
23 //
24 // Choose D and ITERS so total CCT stays small (rec collapses to 1 node
25 // but marker leaves count linearly). D=8, ITERS=100 = 900 throws total.
26 #include <cstdint>
27 #include <cstdio>
28 #define D 8
29 #define ITERS 100
30 static volatile uint64_t sink;
31 static uint64_t buf[ITERS];
32 
33 extern "C" __attribute__((noinline)) void rectry_try_marker(int i) {
34  __asm__ __volatile__("" ::: "memory"); sink ^= (uint64_t)i;
35 }
36 extern "C" __attribute__((noinline)) void rectry_deep_marker(int i) {
37  __asm__ __volatile__("" ::: "memory"); sink ^= (uint64_t)i << 4;
38 }
39 extern "C" __attribute__((noinline)) void rectry_catch_marker(int i) {
40  __asm__ __volatile__("" ::: "memory"); sink ^= (uint64_t)i << 8;
41 }
42 extern "C" __attribute__((noinline)) void rectry_after_marker(int i) {
43  __asm__ __volatile__("" ::: "memory"); sink ^= (uint64_t)i << 12;
44 }
45 extern "C" __attribute__((noinline)) void rectry_outer_try(int i) {
46  __asm__ __volatile__("" ::: "memory"); sink ^= (uint64_t)i << 16;
47 }
48 extern "C" __attribute__((noinline)) void rectry_outer_catch(int i) {
49  __asm__ __volatile__("" ::: "memory"); sink ^= (uint64_t)i << 20;
50 }
51 
52 static void rec(int depth, int iter) {
53  // Stack write so each frame is materialized.
54  volatile uint64_t local = (uint64_t)depth * 0x101ULL + (uint64_t)iter;
55  if (depth == 0) {
56  rectry_deep_marker(iter);
57  buf[iter] = local;
58  throw iter;
59  }
60  try {
61  rectry_try_marker(iter);
62  rec(depth - 1, iter);
63  rectry_after_marker(iter); // unreached: rec always throws
64  } catch (int v) {
65  rectry_catch_marker(iter);
66  buf[iter] ^= (uint64_t)v;
67  throw; // rethrow up to the next frame's catch
68  }
69 }
70 
71 int main(int argc, char** argv) {
72  (void)argc; (void)argv;
73  int caught = 0;
74  for (int i = 0; i < ITERS; ++i) {
75  try {
76  rectry_outer_try(i);
77  rec(D, i);
78  } catch (int v) {
79  rectry_outer_catch(i);
80  caught += (v == i);
81  }
82  }
83  for (int i = 0; i < ITERS; ++i) sink ^= buf[i];
84  fprintf(stderr, "exc_recurse_trycatch: depth=%d iters=%d caught=%d sink=%llx\n",
85  D, ITERS, caught, (unsigned long long)sink);
86  return caught == ITERS ? 0 : 1;
87 }
#define ITERS
int main(int argc, char **argv)
static uint64_t buf[ITERS]
__attribute__((noinline)) void rectry_try_marker(int i)
static void rec(int depth, int iter)
static volatile uint64_t sink
#define D