• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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