Imported Upstream version 2.2.3
[platform/upstream/expat.git] / tests / memcheck.c
1 /* Copyright (c) 2017 The Expat Maintainers
2  * Copying is permitted under the MIT license.  See the file COPYING
3  * for details.
4  *
5  * memcheck.c : debug allocators for the Expat test suite
6  */
7
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include "memcheck.h"
11
12
13 /* Structures to keep track of what has been allocated.  Speed isn't a
14  * big issue for the tests this is required for, so we will use a
15  * doubly-linked list to make deletion easier.
16  */
17
18 typedef struct allocation_entry {
19     struct allocation_entry * next;
20     struct allocation_entry * prev;
21     void * allocation;
22     size_t num_bytes;
23 } AllocationEntry;
24
25 static AllocationEntry *alloc_head = NULL;
26 static AllocationEntry *alloc_tail = NULL;
27
28 static AllocationEntry *find_allocation(void *ptr);
29
30
31 /* Allocate some memory and keep track of it. */
32 void *
33 tracking_malloc(size_t size)
34 {
35     AllocationEntry *entry = malloc(sizeof(AllocationEntry));
36
37     if (entry == NULL) {
38         printf("Allocator failure\n");
39         return NULL;
40     }
41     entry->num_bytes = size;
42     entry->allocation = malloc(size);
43     if (entry->allocation == NULL) {
44         free(entry);
45         return NULL;
46     }
47     entry->next = NULL;
48
49     /* Add to the list of allocations */
50     if (alloc_head == NULL) {
51         entry->prev = NULL;
52         alloc_head = alloc_tail = entry;
53     } else {
54         entry->prev = alloc_tail;
55         alloc_tail->next = entry;
56         alloc_tail = entry;
57     }
58
59     return entry->allocation;
60 }
61
62 static AllocationEntry *
63 find_allocation(void *ptr)
64 {
65     AllocationEntry *entry;
66
67     for (entry = alloc_head; entry != NULL; entry = entry->next) {
68         if (entry->allocation == ptr) {
69             return entry;
70         }
71     }
72     return NULL;
73 }
74
75 /* Free some memory and remove the tracking for it */
76 void
77 tracking_free(void *ptr)
78 {
79     AllocationEntry *entry;
80
81     if (ptr == NULL) {
82         /* There won't be an entry for this */
83         return;
84     }
85
86     entry = find_allocation(ptr);
87     if (entry != NULL) {
88         /* This is the relevant allocation.  Unlink it */
89         if (entry->prev != NULL)
90             entry->prev->next = entry->next;
91         else
92             alloc_head = entry->next;
93         if (entry->next != NULL)
94             entry->next->prev = entry->prev;
95         else
96             alloc_tail = entry->next;
97         free(entry);
98     } else {
99         printf("Attempting to free unallocated memory at %p\n", ptr);
100     }
101     free(ptr);
102 }
103
104 /* Reallocate some memory and keep track of it */
105 void *
106 tracking_realloc(void *ptr, size_t size)
107 {
108     AllocationEntry *entry;
109
110     if (ptr == NULL) {
111         /* By definition, this is equivalent to malloc(size) */
112         return tracking_malloc(size);
113     }
114     if (size == 0) {
115         /* By definition, this is equivalent to free(ptr) */
116         tracking_free(ptr);
117         return NULL;
118     }
119
120     /* Find the allocation entry for this memory */
121     entry = find_allocation(ptr);
122     if (entry == NULL) {
123         printf("Attempting to realloc unallocated memory at %p\n", ptr);
124         entry = malloc(sizeof(AllocationEntry));
125         if (entry == NULL) {
126             printf("Reallocator failure\n");
127             return NULL;
128         }
129         entry->allocation = realloc(ptr, size);
130         if (entry->allocation == NULL) {
131             free(entry);
132             return NULL;
133         }
134
135         /* Add to the list of allocations */
136         entry->next = NULL;
137         if (alloc_head == NULL) {
138             entry->prev = NULL;
139             alloc_head = alloc_tail = entry;
140         } else {
141             entry->prev = alloc_tail;
142             alloc_tail->next = entry;
143             alloc_tail = entry;
144         }
145     } else {
146         entry->allocation = realloc(ptr, size);
147         if (entry->allocation == NULL) {
148             /* Realloc semantics say the original is still allocated */
149             entry->allocation = ptr;
150             return NULL;
151         }
152     }
153
154     entry->num_bytes = size;
155     return entry->allocation;
156 }
157
158 int
159 tracking_report(void)
160 {
161     AllocationEntry *entry;
162
163     if (alloc_head == NULL)
164         return 1;
165
166     /* Otherwise we have allocations that haven't been freed */
167     for (entry = alloc_head; entry != NULL; entry = entry->next)
168     {
169         printf("Allocated %lu bytes at %p\n",
170                 (long unsigned)entry->num_bytes, entry->allocation);
171     }
172     return 0;
173 }