memcheck.c 4.2 KB

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