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