ref: 31c0b0c7e1e9340145e11866c74e20ceddae77f9
parent: 3bed35a90afe33571048edff4b38db07138aaaed
author: Simon Howard <fraggle@soulsphere.org>
date: Sun Apr 26 17:19:40 EDT 2015
zone: Add -zonescan parameter. As further tooling to help debug bugs like #530, add a command line parameter that will scan the zone heap every time a block of memory is freed with Z_Free(), to detect dangling pointers to the freed block.
--- a/src/z_zone.c
+++ b/src/z_zone.c
@@ -64,6 +64,7 @@
static memzone_t *mainzone;
static boolean zero_on_free;
+static boolean scan_on_free;
//
@@ -120,13 +121,55 @@
block->size = mainzone->size - sizeof(memzone_t);
//!
- // Zone memory debugging flag. If set, zero memory after it is freed
+ // Zone memory debugging flag. If set, memory is zeroed after it is freed
// to deliberately break any code that attempts to use it after free.
//
zero_on_free = M_ParmExists("-zonezero");
+
+ //!
+ // Zone memory debugging flag. If set, each time memory is freed, the zone
+ // heap is scanned to look for remaining pointers to the freed block.
+ //
+ scan_on_free = M_ParmExists("-zonescan");
}
+// Scan the zone heap for pointers within the specified range, and warn about
+// any remaining pointers.
+static void ScanForBlock(void *start, void *end)
+{
+ memblock_t *block;
+ void **mem;
+ int i, len, tag;
+ block = mainzone->blocklist.next;
+
+ while (block->next != &mainzone->blocklist)
+ {
+ tag = block->tag;
+
+ if (tag == PU_STATIC || tag == PU_LEVEL || tag == PU_LEVSPEC)
+ {
+ // Scan for pointers on the assumption that pointers are aligned
+ // on word boundaries (word size depending on pointer size):
+ mem = (void **) ((byte *) block + sizeof(memblock_t));
+ len = (block->size - sizeof(memblock_t)) / sizeof(void *);
+
+ for (i = 0; i < len; ++i)
+ {
+ if (start <= mem[i] && mem[i] <= end)
+ {
+ fprintf(stderr,
+ "%p has dangling pointer into freed block "
+ "%p (%p -> %p)\n",
+ mem, start, &mem[i], mem[i]);
+ }
+ }
+ }
+
+ block = block->next;
+ }
+}
+
//
// Z_Free
//
@@ -156,6 +199,11 @@
if (zero_on_free)
{
memset(ptr, 0, block->size - sizeof(memblock_t));
+ }
+ if (scan_on_free)
+ {
+ ScanForBlock(ptr,
+ (byte *) ptr + block->size - sizeof(memblock_t));
}
other = block->prev;