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 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 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 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