18225cc0de2ccf390127b5910dceb7c6185091a38njn#include <stdio.h>
28225cc0de2ccf390127b5910dceb7c6185091a38njn#include <stdlib.h>
38225cc0de2ccf390127b5910dceb7c6185091a38njn#include "leak.h"
48225cc0de2ccf390127b5910dceb7c6185091a38njn#include "../memcheck.h"
58225cc0de2ccf390127b5910dceb7c6185091a38njn
68225cc0de2ccf390127b5910dceb7c6185091a38njn// Pointer chain          AAA Category/output BBB Category/output
78225cc0de2ccf390127b5910dceb7c6185091a38njn// -------------          ------------------- ------------
88225cc0de2ccf390127b5910dceb7c6185091a38njn// p1 ---> AAA            DR / R
98225cc0de2ccf390127b5910dceb7c6185091a38njn// p2 ---> AAA ---> BBB   DR / R              IR / R
108225cc0de2ccf390127b5910dceb7c6185091a38njn// p3      AAA            DL / L
118225cc0de2ccf390127b5910dceb7c6185091a38njn// p4      AAA ---> BBB   DL / I              IL / L
128225cc0de2ccf390127b5910dceb7c6185091a38njn// p5 -?-> AAA            (y)DR, (n)DL / P
138225cc0de2ccf390127b5910dceb7c6185091a38njn// p6 ---> AAA -?-> BBB   DR / R              (y)IR, (n)DL / P
148225cc0de2ccf390127b5910dceb7c6185091a38njn// p7 -?-> AAA ---> BBB   (y)DR, (n)DL / P    (y)IR, (n)IL / P
158225cc0de2ccf390127b5910dceb7c6185091a38njn// p8 -?-> AAA -?-> BBB   (y)DR, (n)DL / P    (y,y)IR, (n,y)IL, (_,n)DL / P
168225cc0de2ccf390127b5910dceb7c6185091a38njn// p9      AAA -?-> BBB   DL / L              (y)IL, (n)DL / I
178225cc0de2ccf390127b5910dceb7c6185091a38njn//
188225cc0de2ccf390127b5910dceb7c6185091a38njn// Pointer chain legend:
198225cc0de2ccf390127b5910dceb7c6185091a38njn// - pN: a root set pointer
208225cc0de2ccf390127b5910dceb7c6185091a38njn// - AAA, BBB: heap blocks
218225cc0de2ccf390127b5910dceb7c6185091a38njn// - --->: a start-pointer
228225cc0de2ccf390127b5910dceb7c6185091a38njn// - -?->: an interior-pointer
238225cc0de2ccf390127b5910dceb7c6185091a38njn//
248225cc0de2ccf390127b5910dceb7c6185091a38njn// Category legend:
258225cc0de2ccf390127b5910dceb7c6185091a38njn// - DR: Directly reachable
268225cc0de2ccf390127b5910dceb7c6185091a38njn// - IR: Indirectly reachable
278225cc0de2ccf390127b5910dceb7c6185091a38njn// - DL: Directly lost
288225cc0de2ccf390127b5910dceb7c6185091a38njn// - IL: Indirectly lost
298225cc0de2ccf390127b5910dceb7c6185091a38njn// - (y)XY: it's XY if the interior-pointer is a real pointer
308225cc0de2ccf390127b5910dceb7c6185091a38njn// - (n)XY: it's XY if the interior-pointer is not a real pointer
318225cc0de2ccf390127b5910dceb7c6185091a38njn// - (_)XY: it's XY in either case
328225cc0de2ccf390127b5910dceb7c6185091a38njn//
338225cc0de2ccf390127b5910dceb7c6185091a38njn// How we handle the 9 cases:
348225cc0de2ccf390127b5910dceb7c6185091a38njn// - "directly lost":    case 3
358225cc0de2ccf390127b5910dceb7c6185091a38njn// - "indirectly lost":  cases 4, 9
368225cc0de2ccf390127b5910dceb7c6185091a38njn// - "possibly lost":    cases 5..8
378225cc0de2ccf390127b5910dceb7c6185091a38njn// - "still reachable":  cases 1, 2
388225cc0de2ccf390127b5910dceb7c6185091a38njn
398225cc0de2ccf390127b5910dceb7c6185091a38njn
408225cc0de2ccf390127b5910dceb7c6185091a38njntypedef
418225cc0de2ccf390127b5910dceb7c6185091a38njn   struct _Node {
428225cc0de2ccf390127b5910dceb7c6185091a38njn      struct _Node* next;
438225cc0de2ccf390127b5910dceb7c6185091a38njn      // Padding ensures the structu is the same size on 32-bit and 64-bit
448225cc0de2ccf390127b5910dceb7c6185091a38njn      // machines.
458225cc0de2ccf390127b5910dceb7c6185091a38njn      char padding[8 - sizeof(struct _Node*)];
468225cc0de2ccf390127b5910dceb7c6185091a38njn   } Node;
478225cc0de2ccf390127b5910dceb7c6185091a38njn
488225cc0de2ccf390127b5910dceb7c6185091a38njnNode* mk(Node* next)
498225cc0de2ccf390127b5910dceb7c6185091a38njn{
508225cc0de2ccf390127b5910dceb7c6185091a38njn   // We allocate two nodes, so we can do p+1 and still point within the
518225cc0de2ccf390127b5910dceb7c6185091a38njn   // block.
528225cc0de2ccf390127b5910dceb7c6185091a38njn   Node* x = malloc(2 * sizeof(Node));
538225cc0de2ccf390127b5910dceb7c6185091a38njn   x->next = next;
548225cc0de2ccf390127b5910dceb7c6185091a38njn   return x;
558225cc0de2ccf390127b5910dceb7c6185091a38njn}
568225cc0de2ccf390127b5910dceb7c6185091a38njn
578225cc0de2ccf390127b5910dceb7c6185091a38njn// These are definite roots.
588225cc0de2ccf390127b5910dceb7c6185091a38njnNode* p1;
598225cc0de2ccf390127b5910dceb7c6185091a38njnNode* p2;
608225cc0de2ccf390127b5910dceb7c6185091a38njnNode* p3;
618225cc0de2ccf390127b5910dceb7c6185091a38njnNode* p4;
628225cc0de2ccf390127b5910dceb7c6185091a38njnNode* p5;
638225cc0de2ccf390127b5910dceb7c6185091a38njnNode* p6;
648225cc0de2ccf390127b5910dceb7c6185091a38njnNode* p7;
658225cc0de2ccf390127b5910dceb7c6185091a38njnNode* p8;
668225cc0de2ccf390127b5910dceb7c6185091a38njnNode* p9;
678225cc0de2ccf390127b5910dceb7c6185091a38njn
68402c1a1c1dd72673a2adcfd5bded97180507a727njnvoid f(void)
698225cc0de2ccf390127b5910dceb7c6185091a38njn{
708225cc0de2ccf390127b5910dceb7c6185091a38njn   p1 = mk(NULL);       // Case 1: 16/1 still reachable
718225cc0de2ccf390127b5910dceb7c6185091a38njn
728225cc0de2ccf390127b5910dceb7c6185091a38njn   p2 = mk(mk(NULL));   // Case 2: 16/1 still reachable
738225cc0de2ccf390127b5910dceb7c6185091a38njn                                // 16/1 still reachable
748225cc0de2ccf390127b5910dceb7c6185091a38njn   (void)mk(NULL);      // Case 3: 16/1 definitely lost
758225cc0de2ccf390127b5910dceb7c6185091a38njn
768225cc0de2ccf390127b5910dceb7c6185091a38njn   (void)mk(mk(NULL));  // Case 4: 16/1 indirectly lost (counted again below!)
778225cc0de2ccf390127b5910dceb7c6185091a38njn                                // 32(16d,16i)/1 definitely lost (double count!)
788225cc0de2ccf390127b5910dceb7c6185091a38njn   p5 = mk(NULL);       // Case 5: 16/1 possibly lost (ok)
798225cc0de2ccf390127b5910dceb7c6185091a38njn   p5++;
808225cc0de2ccf390127b5910dceb7c6185091a38njn
818225cc0de2ccf390127b5910dceb7c6185091a38njn   p6 = mk(mk(NULL));   // Case 6: 16/1 still reachable
828225cc0de2ccf390127b5910dceb7c6185091a38njn   (p6->next)++;                // 16/1 possibly lost
838225cc0de2ccf390127b5910dceb7c6185091a38njn
848225cc0de2ccf390127b5910dceb7c6185091a38njn   p7 = mk(mk(NULL));   // Case 7: 16/1 possibly lost
858225cc0de2ccf390127b5910dceb7c6185091a38njn   p7++;                        // 16/1 possibly lost
868225cc0de2ccf390127b5910dceb7c6185091a38njn
878225cc0de2ccf390127b5910dceb7c6185091a38njn   p8 = mk(mk(NULL));   // Case 8: 16/1 possibly lost
888225cc0de2ccf390127b5910dceb7c6185091a38njn   (p8->next)++;                // 16/1 possibly lost
898225cc0de2ccf390127b5910dceb7c6185091a38njn   p8++;
908225cc0de2ccf390127b5910dceb7c6185091a38njn
918225cc0de2ccf390127b5910dceb7c6185091a38njn   p9 = mk(mk(NULL));   // Case 9: 16/1 indirectly lost (counted again below!)
928225cc0de2ccf390127b5910dceb7c6185091a38njn   (p9->next)++;                // 32(16d,16i)/1 definitely lost (double count!)
938225cc0de2ccf390127b5910dceb7c6185091a38njn   p9 = NULL;
94402c1a1c1dd72673a2adcfd5bded97180507a727njn}
95402c1a1c1dd72673a2adcfd5bded97180507a727njn
96402c1a1c1dd72673a2adcfd5bded97180507a727njnint main(void)
97402c1a1c1dd72673a2adcfd5bded97180507a727njn{
98402c1a1c1dd72673a2adcfd5bded97180507a727njn   DECLARE_LEAK_COUNTERS;
99402c1a1c1dd72673a2adcfd5bded97180507a727njn
100402c1a1c1dd72673a2adcfd5bded97180507a727njn   GET_INITIAL_LEAK_COUNTS;
101402c1a1c1dd72673a2adcfd5bded97180507a727njn
102402c1a1c1dd72673a2adcfd5bded97180507a727njn   // Originally, this program did all the work in main(), but on some
103402c1a1c1dd72673a2adcfd5bded97180507a727njn   // platforms (x86/Darwin and AMD64/Linux with --enable-only32bit) stray
104402c1a1c1dd72673a2adcfd5bded97180507a727njn   // pointers to supposedly-lost heap blocks were being left on the stack,
105402c1a1c1dd72673a2adcfd5bded97180507a727njn   // thus making them reachable.  Doing the allocations in f() and the leak
106402c1a1c1dd72673a2adcfd5bded97180507a727njn   // counting in main() avoids the problem.
107402c1a1c1dd72673a2adcfd5bded97180507a727njn   f();
1088225cc0de2ccf390127b5910dceb7c6185091a38njn
109a5dda3e6bf767113c056a94e378417c8a1468dbbsewardj   CLEAR_CALLER_SAVED_REGS;
1108225cc0de2ccf390127b5910dceb7c6185091a38njn   GET_FINAL_LEAK_COUNTS;
1118225cc0de2ccf390127b5910dceb7c6185091a38njn
1128225cc0de2ccf390127b5910dceb7c6185091a38njn   PRINT_LEAK_COUNTS(stderr);
1138225cc0de2ccf390127b5910dceb7c6185091a38njn
1148225cc0de2ccf390127b5910dceb7c6185091a38njn   return 0;
1158225cc0de2ccf390127b5910dceb7c6185091a38njn}
116