1ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <stdio.h>
2ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <stdlib.h>
3ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "leak.h"
4ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "../memcheck.h"
5ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Pointer chain          AAA Category/output BBB Category/output
7ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// -------------          ------------------- ------------
8ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// p1 ---> AAA            DR / R
9ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// p2 ---> AAA ---> BBB   DR / R              IR / R
10ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// p3      AAA            DL / L
11ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// p4      AAA ---> BBB   DL / I              IL / L
12ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// p5 -?-> AAA            (y)DR, (n)DL / P
13ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// p6 ---> AAA -?-> BBB   DR / R              (y)IR, (n)DL / P
14ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// p7 -?-> AAA ---> BBB   (y)DR, (n)DL / P    (y)IR, (n)IL / P
15ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// p8 -?-> AAA -?-> BBB   (y)DR, (n)DL / P    (y,y)IR, (n,y)IL, (_,n)DL / P
16ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// p9      AAA -?-> BBB   DL / L              (y)IL, (n)DL / I
17ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//
18ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Pointer chain legend:
19ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - pN: a root set pointer
20ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - AAA, BBB: heap blocks
21ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - --->: a start-pointer
22ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - -?->: an interior-pointer
23ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//
24ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Category legend:
25ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - DR: Directly reachable
26ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - IR: Indirectly reachable
27ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - DL: Directly lost
28ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - IL: Indirectly lost
29ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - (y)XY: it's XY if the interior-pointer is a real pointer
30ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - (n)XY: it's XY if the interior-pointer is not a real pointer
31ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - (_)XY: it's XY in either case
32ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//
33ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// How we handle the 9 cases:
34ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - "directly lost":    case 3
35ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - "indirectly lost":  cases 4, 9
36ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - "possibly lost":    cases 5..8
37ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - "still reachable":  cases 1, 2
38ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
39ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
40ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browntypedef
41ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   struct _Node {
42ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      struct _Node* next;
43ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // Padding ensures the structu is the same size on 32-bit and 64-bit
44ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // machines.
45ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      char padding[8 - sizeof(struct _Node*)];
46ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } Node;
47ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
48ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownNode* mk(Node* next)
49ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
50ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // We allocate two nodes, so we can do p+1 and still point within the
51ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // block.
52ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Node* x = malloc(2 * sizeof(Node));
53ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   x->next = next;
54ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return x;
55ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
56ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
57ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// These are definite roots.
58ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownNode* p1;
59ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownNode* p2;
60ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownNode* p3;
61ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownNode* p4;
62ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownNode* p5;
63ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownNode* p6;
64ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownNode* p7;
65ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownNode* p8;
66ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownNode* p9;
67ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
68ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid f(void)
69ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
70ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   p1 = mk(NULL);       // Case 1: 16/1 still reachable
71ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
72ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   p2 = mk(mk(NULL));   // Case 2: 16/1 still reachable
73ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                // 16/1 still reachable
74ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   (void)mk(NULL);      // Case 3: 16/1 definitely lost
75ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
76ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   (void)mk(mk(NULL));  // Case 4: 16/1 indirectly lost (counted again below!)
77ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                // 32(16d,16i)/1 definitely lost (double count!)
78ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   p5 = mk(NULL);       // Case 5: 16/1 possibly lost (ok)
79ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   p5++;
80ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
81ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   p6 = mk(mk(NULL));   // Case 6: 16/1 still reachable
82ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   (p6->next)++;                // 16/1 possibly lost
83ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
84ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   p7 = mk(mk(NULL));   // Case 7: 16/1 possibly lost
85ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   p7++;                        // 16/1 possibly lost
86ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
87ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   p8 = mk(mk(NULL));   // Case 8: 16/1 possibly lost
88ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   (p8->next)++;                // 16/1 possibly lost
89ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   p8++;
90ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
91ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   p9 = mk(mk(NULL));   // Case 9: 16/1 indirectly lost (counted again below!)
92ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   (p9->next)++;                // 32(16d,16i)/1 definitely lost (double count!)
93ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   p9 = NULL;
94ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
95ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
96ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownint main(void)
97ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
98ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DECLARE_LEAK_COUNTERS;
99ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   GET_INITIAL_LEAK_COUNTS;
101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Originally, this program did all the work in main(), but on some
103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // platforms (x86/Darwin and AMD64/Linux with --enable-only32bit) stray
104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // pointers to supposedly-lost heap blocks were being left on the stack,
105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // thus making them reachable.  Doing the allocations in f() and the leak
106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // counting in main() avoids the problem.
107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   f();
108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   CLEAR_CALLER_SAVED_REGS;
110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   GET_FINAL_LEAK_COUNTS;
111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   PRINT_LEAK_COUNTS(stderr);
113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return 0;
115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
116