12e724bc9Sbluhm /* Debug allocators for the Expat test suite
22e724bc9Sbluhm __ __ _
32e724bc9Sbluhm ___\ \/ /_ __ __ _| |_
42e724bc9Sbluhm / _ \\ /| '_ \ / _` | __|
52e724bc9Sbluhm | __// \| |_) | (_| | |_
62e724bc9Sbluhm \___/_/\_\ .__/ \__,_|\__|
72e724bc9Sbluhm |_| XML parser
82e724bc9Sbluhm
908819b41Sbluhm Copyright (c) 2017 Rhodri James <rhodri@wildebeest.org.uk>
10*bd8f1dc3Sbluhm Copyright (c) 2017-2023 Sebastian Pipping <sebastian@pipping.org>
11*bd8f1dc3Sbluhm Copyright (c) 2022 Sean McBride <sean@rogue-research.com>
122e724bc9Sbluhm Licensed under the MIT license:
132e724bc9Sbluhm
142e724bc9Sbluhm Permission is hereby granted, free of charge, to any person obtaining
152e724bc9Sbluhm a copy of this software and associated documentation files (the
162e724bc9Sbluhm "Software"), to deal in the Software without restriction, including
172e724bc9Sbluhm without limitation the rights to use, copy, modify, merge, publish,
182e724bc9Sbluhm distribute, sublicense, and/or sell copies of the Software, and to permit
192e724bc9Sbluhm persons to whom the Software is furnished to do so, subject to the
202e724bc9Sbluhm following conditions:
212e724bc9Sbluhm
222e724bc9Sbluhm The above copyright notice and this permission notice shall be included
232e724bc9Sbluhm in all copies or substantial portions of the Software.
242e724bc9Sbluhm
252e724bc9Sbluhm THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
262e724bc9Sbluhm EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
272e724bc9Sbluhm MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
282e724bc9Sbluhm NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
292e724bc9Sbluhm DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
302e724bc9Sbluhm OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
312e724bc9Sbluhm USE OR OTHER DEALINGS IN THE SOFTWARE.
3233ab7b2bSbluhm */
3333ab7b2bSbluhm
3433ab7b2bSbluhm #include <stdio.h>
3533ab7b2bSbluhm #include <stdlib.h>
3633ab7b2bSbluhm #include "memcheck.h"
3733ab7b2bSbluhm
3833ab7b2bSbluhm /* Structures to keep track of what has been allocated. Speed isn't a
3933ab7b2bSbluhm * big issue for the tests this is required for, so we will use a
4033ab7b2bSbluhm * doubly-linked list to make deletion easier.
4133ab7b2bSbluhm */
4233ab7b2bSbluhm
4333ab7b2bSbluhm typedef struct allocation_entry {
4433ab7b2bSbluhm struct allocation_entry *next;
4533ab7b2bSbluhm struct allocation_entry *prev;
4633ab7b2bSbluhm void *allocation;
4733ab7b2bSbluhm size_t num_bytes;
4833ab7b2bSbluhm } AllocationEntry;
4933ab7b2bSbluhm
5033ab7b2bSbluhm static AllocationEntry *alloc_head = NULL;
5133ab7b2bSbluhm static AllocationEntry *alloc_tail = NULL;
5233ab7b2bSbluhm
53*bd8f1dc3Sbluhm static AllocationEntry *find_allocation(const void *ptr);
5433ab7b2bSbluhm
5533ab7b2bSbluhm /* Allocate some memory and keep track of it. */
5633ab7b2bSbluhm void *
tracking_malloc(size_t size)5728ce3119Sbluhm tracking_malloc(size_t size) {
58*bd8f1dc3Sbluhm AllocationEntry *const entry
59*bd8f1dc3Sbluhm = (AllocationEntry *)malloc(sizeof(AllocationEntry));
6033ab7b2bSbluhm
6133ab7b2bSbluhm if (entry == NULL) {
6233ab7b2bSbluhm printf("Allocator failure\n");
6333ab7b2bSbluhm return NULL;
6433ab7b2bSbluhm }
6533ab7b2bSbluhm entry->num_bytes = size;
6633ab7b2bSbluhm entry->allocation = malloc(size);
6733ab7b2bSbluhm if (entry->allocation == NULL) {
6833ab7b2bSbluhm free(entry);
6933ab7b2bSbluhm return NULL;
7033ab7b2bSbluhm }
7133ab7b2bSbluhm entry->next = NULL;
7233ab7b2bSbluhm
7333ab7b2bSbluhm /* Add to the list of allocations */
7433ab7b2bSbluhm if (alloc_head == NULL) {
7533ab7b2bSbluhm entry->prev = NULL;
7633ab7b2bSbluhm alloc_head = alloc_tail = entry;
7733ab7b2bSbluhm } else {
7833ab7b2bSbluhm entry->prev = alloc_tail;
7933ab7b2bSbluhm alloc_tail->next = entry;
8033ab7b2bSbluhm alloc_tail = entry;
8133ab7b2bSbluhm }
8233ab7b2bSbluhm
8333ab7b2bSbluhm return entry->allocation;
8433ab7b2bSbluhm }
8533ab7b2bSbluhm
8633ab7b2bSbluhm static AllocationEntry *
find_allocation(const void * ptr)87*bd8f1dc3Sbluhm find_allocation(const void *ptr) {
8833ab7b2bSbluhm AllocationEntry *entry;
8933ab7b2bSbluhm
9033ab7b2bSbluhm for (entry = alloc_head; entry != NULL; entry = entry->next) {
9133ab7b2bSbluhm if (entry->allocation == ptr) {
9233ab7b2bSbluhm return entry;
9333ab7b2bSbluhm }
9433ab7b2bSbluhm }
9533ab7b2bSbluhm return NULL;
9633ab7b2bSbluhm }
9733ab7b2bSbluhm
9833ab7b2bSbluhm /* Free some memory and remove the tracking for it */
9933ab7b2bSbluhm void
tracking_free(void * ptr)10028ce3119Sbluhm tracking_free(void *ptr) {
10133ab7b2bSbluhm AllocationEntry *entry;
10233ab7b2bSbluhm
10333ab7b2bSbluhm if (ptr == NULL) {
10433ab7b2bSbluhm /* There won't be an entry for this */
10533ab7b2bSbluhm return;
10633ab7b2bSbluhm }
10733ab7b2bSbluhm
10833ab7b2bSbluhm entry = find_allocation(ptr);
10933ab7b2bSbluhm if (entry != NULL) {
11033ab7b2bSbluhm /* This is the relevant allocation. Unlink it */
11133ab7b2bSbluhm if (entry->prev != NULL)
11233ab7b2bSbluhm entry->prev->next = entry->next;
11333ab7b2bSbluhm else
11433ab7b2bSbluhm alloc_head = entry->next;
11533ab7b2bSbluhm if (entry->next != NULL)
11633ab7b2bSbluhm entry->next->prev = entry->prev;
11733ab7b2bSbluhm else
11833ab7b2bSbluhm alloc_tail = entry->next;
11933ab7b2bSbluhm free(entry);
12033ab7b2bSbluhm } else {
12133ab7b2bSbluhm printf("Attempting to free unallocated memory at %p\n", ptr);
12233ab7b2bSbluhm }
12333ab7b2bSbluhm free(ptr);
12433ab7b2bSbluhm }
12533ab7b2bSbluhm
12633ab7b2bSbluhm /* Reallocate some memory and keep track of it */
12733ab7b2bSbluhm void *
tracking_realloc(void * ptr,size_t size)12828ce3119Sbluhm tracking_realloc(void *ptr, size_t size) {
12933ab7b2bSbluhm AllocationEntry *entry;
13033ab7b2bSbluhm
13133ab7b2bSbluhm if (ptr == NULL) {
13233ab7b2bSbluhm /* By definition, this is equivalent to malloc(size) */
13333ab7b2bSbluhm return tracking_malloc(size);
13433ab7b2bSbluhm }
13533ab7b2bSbluhm if (size == 0) {
13633ab7b2bSbluhm /* By definition, this is equivalent to free(ptr) */
13733ab7b2bSbluhm tracking_free(ptr);
13833ab7b2bSbluhm return NULL;
13933ab7b2bSbluhm }
14033ab7b2bSbluhm
14133ab7b2bSbluhm /* Find the allocation entry for this memory */
14233ab7b2bSbluhm entry = find_allocation(ptr);
14333ab7b2bSbluhm if (entry == NULL) {
14433ab7b2bSbluhm printf("Attempting to realloc unallocated memory at %p\n", ptr);
145*bd8f1dc3Sbluhm entry = (AllocationEntry *)malloc(sizeof(AllocationEntry));
14633ab7b2bSbluhm if (entry == NULL) {
14733ab7b2bSbluhm printf("Reallocator failure\n");
14833ab7b2bSbluhm return NULL;
14933ab7b2bSbluhm }
15033ab7b2bSbluhm entry->allocation = realloc(ptr, size);
15133ab7b2bSbluhm if (entry->allocation == NULL) {
15233ab7b2bSbluhm free(entry);
15333ab7b2bSbluhm return NULL;
15433ab7b2bSbluhm }
15533ab7b2bSbluhm
15633ab7b2bSbluhm /* Add to the list of allocations */
15733ab7b2bSbluhm entry->next = NULL;
15833ab7b2bSbluhm if (alloc_head == NULL) {
15933ab7b2bSbluhm entry->prev = NULL;
16033ab7b2bSbluhm alloc_head = alloc_tail = entry;
16133ab7b2bSbluhm } else {
16233ab7b2bSbluhm entry->prev = alloc_tail;
16333ab7b2bSbluhm alloc_tail->next = entry;
16433ab7b2bSbluhm alloc_tail = entry;
16533ab7b2bSbluhm }
16633ab7b2bSbluhm } else {
167*bd8f1dc3Sbluhm void *const reallocated = realloc(ptr, size);
168*bd8f1dc3Sbluhm if (reallocated == NULL) {
16933ab7b2bSbluhm return NULL;
17033ab7b2bSbluhm }
171*bd8f1dc3Sbluhm entry->allocation = reallocated;
17233ab7b2bSbluhm }
17333ab7b2bSbluhm
17433ab7b2bSbluhm entry->num_bytes = size;
17533ab7b2bSbluhm return entry->allocation;
17633ab7b2bSbluhm }
17733ab7b2bSbluhm
17833ab7b2bSbluhm int
tracking_report(void)17928ce3119Sbluhm tracking_report(void) {
18033ab7b2bSbluhm AllocationEntry *entry;
18133ab7b2bSbluhm
18233ab7b2bSbluhm if (alloc_head == NULL)
18333ab7b2bSbluhm return 1;
18433ab7b2bSbluhm
18533ab7b2bSbluhm /* Otherwise we have allocations that haven't been freed */
18628ce3119Sbluhm for (entry = alloc_head; entry != NULL; entry = entry->next) {
18728ce3119Sbluhm printf("Allocated %lu bytes at %p\n", (long unsigned)entry->num_bytes,
18828ce3119Sbluhm entry->allocation);
18933ab7b2bSbluhm }
19033ab7b2bSbluhm return 0;
19133ab7b2bSbluhm }
192