CCTLib
Calling-context and data-object attribution library for Intel Pin
rec_indirect_only.cpp
Go to the documentation of this file.
1 // Indirect self-recursion via function pointer. The classifier does
2 // NOT see this as self-recursion (INS_IsDirectControlFlow is false),
3 // so it falls back to today's behavior: CCT grows one node per
4 // activation. Test asserts (a) no crash, (b) correct final result.
5 // This locks in the "graceful degradation" contract for the
6 // indirect-only case documented in the design.
7 #include <cstdint>
8 #include <cstdio>
9 
10 static volatile uint64_t sink;
11 
12 typedef uint64_t (*RecFn)(int);
13 static RecFn g_next;
14 
15 static uint64_t indirect_rec(int n) {
16  if (n <= 0) return 1;
17  // Indirect call. g_next is set to point back at indirect_rec
18  // itself; Pin's classifier sees an indirect call and marks the
19  // site as not-direct-self-recursive.
20  return 1 + g_next(n - 1);
21 }
22 
23 int main(int argc, char** argv) {
24  (void)argc; (void)argv;
26  // Depth 12 -> 12 physical frames of indirect_rec plus main.
27  // Kept comfortably under cctlib's MAX_CCT_PRINT_DEPTH=20 so the
28  // shape check assertion can see distinct chain signatures per
29  // uncollapsed frame -- if we ever regressed by accidentally
30  // collapsing indirect recursion, chainCountForFn("indirect_rec")
31  // would drop and the assertion would fail.
32  uint64_t r = indirect_rec(12);
33  sink ^= r;
34  fprintf(stderr, "rec_indirect_only: r=%llu sink=%llx\n",
35  (unsigned long long)r, (unsigned long long)sink);
36  return r == 13 ? 0 : 1;
37 }
static uint64_t indirect_rec(int n)
int main(int argc, char **argv)
static RecFn g_next
uint64_t(* RecFn)(int)
static volatile uint64_t sink