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