File: leak-tree.c

package info (click to toggle)
valgrind 1%3A3.14.0-3
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 156,980 kB
  • sloc: ansic: 728,128; exp: 26,134; xml: 22,268; cpp: 7,638; asm: 7,312; makefile: 6,102; perl: 5,910; sh: 5,717
file content (72 lines) | stat: -rw-r--r-- 1,363 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#include <stdio.h>
#include <stdlib.h>
#include "leak.h"
#include "../memcheck.h"

/* We build this tree:
  
           A
         /   \
        B     C
       / \   / \ 
      D   E F   G
  
   Then we leak D and C-F-G.
*/

typedef
   struct _Node {
      struct _Node *l;
      struct _Node *r;
      // Padding ensures the structu is the same size on 32-bit and 64-bit
      // machines.
      char padding[16 - 2*sizeof(struct _Node*)];
   } Node;

Node* mk(void)
{
   Node *x = malloc(sizeof(Node));
   x->l = NULL;
   x->r = NULL;
   return x;
}

// This is a definite root.
Node* t;

void f(void)
{
   // Building like this rather than "t = mk(mk(mk(NULL, NULL), ...)" seems to
   // help avoid leaving pointers on the stack to supposedly-leaked blocks.
   t       = mk();   // A
   t->l    = mk();   // B
   t->r    = mk();   // C  (48(16d,32i)/1 definitely leaked from here)
   t->l->l = mk();   // D  (16/1 definitely leaked from here)
   t->l->r = mk();   // E
   t->r->l = mk();   // F
   t->r->r = mk();   // G

   // Sever B->D, leaking D
   t->l->l = NULL;
 
   // Sever A->C, leaking C-F-G
   t->r = NULL;
}

int main(void)
{
   DECLARE_LEAK_COUNTERS;

   GET_INITIAL_LEAK_COUNTS;

   // See leak-cases.c for why we do the work in f().
   f();

   CLEAR_CALLER_SAVED_REGS;
   GET_FINAL_LEAK_COUNTS;

   PRINT_LEAK_COUNTS(stderr);

   return 0;
}