From dd09a0706ab09a54f5fbb05c63420c86375b45bf Mon Sep 17 00:00:00 2001 From: Robin Watts Date: Thu, 26 Apr 2012 15:11:18 +0100 Subject: Memento tweaks; add Memento_breakOnFree/Realloc functionality. Memento_breakOnFree(address) will cause a breakpoint when the block including a given address is freed. If the block is realloced (and hence moves elsewhere) the breakpoint is not triggered until the new block is itself freed. Memento_breakOnRealloc(address) will cause a breakpoint when the block including a given address is freed or realloced. --- gs/base/memento.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- gs/base/memento.h | 36 +++++++++++---------- 2 files changed, 108 insertions(+), 21 deletions(-) diff --git a/gs/base/memento.c b/gs/base/memento.c index 22ac5e5a2..44b088057 100644 --- a/gs/base/memento.c +++ b/gs/base/memento.c @@ -95,7 +95,9 @@ enum { enum { Memento_Flag_OldBlock = 1, - Memento_Flag_HasParent = 2 + Memento_Flag_HasParent = 2, + Memento_Flag_BreakOnFree = 4, + Memento_Flag_BreakOnRealloc = 8 }; /* When we list leaked blocks at the end of execution, we search for pointers @@ -541,7 +543,7 @@ int Memento_listBlocksNested(void) b->flags &= ~Memento_Flag_HasParent; b->child = NULL; b->sibling = NULL; - b->parent = NULL; + b->parent = NULL; } qsort(blocks, count, sizeof(void *), ptrcmp); @@ -562,11 +564,11 @@ int Memento_listBlocksNested(void) if (r) { /* Found child */ Memento_BlkHeader *child = MEMBLK_FROMBLK(*r); - Memento_BlkHeader *parent; + Memento_BlkHeader *parent; /* We're assuming tree structure, not graph - ignore second * and subsequent pointers. */ - if (child->parent != NULL) + if (child->parent != NULL) continue; if (child->flags & Memento_Flag_HasParent) continue; @@ -581,7 +583,7 @@ int Memento_listBlocksNested(void) child->sibling = b->child; b->child = child; - child->parent = b; + child->parent = b; child->flags |= Memento_Flag_HasParent; } } @@ -1029,6 +1031,9 @@ void Memento_free(void *blk) if (checkBlock(memblk, "free")) return; + if (memblk->flags & Memento_Flag_BreakOnFree) + Memento_breakpoint(); + VALGRIND_MAKE_MEM_DEFINED(memblk, sizeof(*memblk)); globals.alloc -= memblk->rawsize; globals.numFrees++; @@ -1068,6 +1073,9 @@ void *Memento_realloc(void *blk, size_t newsize) if (checkBlock(memblk, "realloc")) return NULL; + if (memblk->flags & Memento_Flag_BreakOnRealloc) + Memento_breakpoint(); + if (globals.maxMemory != 0 && globals.alloc - memblk->rawsize + newsize > globals.maxMemory) return NULL; @@ -1085,6 +1093,7 @@ void *Memento_realloc(void *blk, size_t newsize) globals.alloc += newsize; if (globals.peakAlloc < globals.alloc) globals.peakAlloc = globals.alloc; + newmemblk->flags = memblk->flags; if (newmemblk->rawsize < newsize) { char *newbytes = ((char *)MEMBLK_TOBLK(newmemblk))+newmemblk->rawsize; #ifndef MEMENTO_LEAKONLY @@ -1296,6 +1305,72 @@ int Memento_find(void *a) return 0; } +void Memento_breakOnFree(void *a) +{ + findBlkData data; + + data.addr = a; + data.blk = NULL; + data.flags = 0; + Memento_appBlocks(&globals.used, Memento_containsAddr, &data); + if (data.blk != NULL) { + fprintf(stderr, "Will stop when address 0x%p (in %sallocated block ", + data.addr, + (data.flags == 1 ? "" : (data.flags == 2 ? + "preguard of " : "postguard of "))); + showBlock(data.blk, ' '); + fprintf(stderr, ") is freed\n"); + data.blk->flags |= Memento_Flag_BreakOnFree; + return; + } + data.blk = NULL; + data.flags = 0; + Memento_appBlocks(&globals.free, Memento_containsAddr, &data); + if (data.blk != NULL) { + fprintf(stderr, "Can't stop on free; address 0x%p is in %sfreed block ", + data.addr, + (data.flags == 1 ? "" : (data.flags == 2 ? + "preguard of " : "postguard of "))); + showBlock(data.blk, ' '); + fprintf(stderr, "\n"); + return; + } + fprintf(stderr, "Can't stop on free; address 0x%p is not in a known block.\n"); +} + +void Memento_breakOnRealloc(void *a) +{ + findBlkData data; + + data.addr = a; + data.blk = NULL; + data.flags = 0; + Memento_appBlocks(&globals.used, Memento_containsAddr, &data); + if (data.blk != NULL) { + fprintf(stderr, "Will stop when address 0x%p (in %sallocated block ", + data.addr, + (data.flags == 1 ? "" : (data.flags == 2 ? + "preguard of " : "postguard of "))); + showBlock(data.blk, ' '); + fprintf(stderr, ") is freed (or realloced)\n"); + data.blk->flags |= Memento_Flag_BreakOnFree | Memento_Flag_BreakOnRealloc; + return; + } + data.blk = NULL; + data.flags = 0; + Memento_appBlocks(&globals.free, Memento_containsAddr, &data); + if (data.blk != NULL) { + fprintf(stderr, "Can't stop on free/realloc; address 0x%p is in %sfreed block ", + data.addr, + (data.flags == 1 ? "" : (data.flags == 2 ? + "preguard of " : "postguard of "))); + showBlock(data.blk, ' '); + fprintf(stderr, "\n"); + return; + } + fprintf(stderr, "Can't stop on free/realloc; address 0x%p is not in a known block.\n"); +} + int Memento_failAt(int i) { globals.failAt = i; @@ -1363,6 +1438,14 @@ int (Memento_failAt)(int i) return 0; } +void (Memento_breakOnFree)(void *a) +{ +} + +void (Memento_breakOnRealloc)(void *a) +{ +} + #undef Memento_malloc #undef Memento_free #undef Memento_realloc diff --git a/gs/base/memento.h b/gs/base/memento.h index e4b7778f0..960af8131 100644 --- a/gs/base/memento.h +++ b/gs/base/memento.h @@ -169,6 +169,8 @@ int Memento_check(void); int Memento_setParanoia(int); int Memento_paranoidAt(int); int Memento_breakAt(int); +void Memento_breakOnFree(void *a); +void Memento_breakOnRealloc(void *a); int Memento_getBlockNum(void *); int Memento_find(void *a); void Memento_breakpoint(void); @@ -201,22 +203,24 @@ void *Memento_calloc(size_t, size_t); #define Memento_realloc MEMENTO_UNDERLYING_REALLOC #define Memento_calloc MEMENTO_UNDERLYING_CALLOC -#define Memento_checkBlock(A) 0 -#define Memento_checkAllMemory() 0 -#define Memento_check() 0 -#define Memento_setParanoia(A) 0 -#define Memento_paranoidAt(A) 0 -#define Memento_breakAt(A) 0 -#define Memento_getBlockNum(A) 0 -#define Memento_find(A) 0 -#define Memento_breakpoint() do {} while (0) -#define Memento_failAt(A) 0 -#define Memento_failThisEvent() 0 -#define Memento_listBlocks() do {} while (0) -#define Memento_listNewBlocks() do {} while (0) -#define Memento_setMax(A) 0 -#define Memento_stats() do {} while (0) -#define Memento_label(A,B) (A) +#define Memento_checkBlock(A) 0 +#define Memento_checkAllMemory() 0 +#define Memento_check() 0 +#define Memento_setParanoia(A) 0 +#define Memento_paranoidAt(A) 0 +#define Memento_breakAt(A) 0 +#define Memento_breakOnFree(A) 0 +#define Memento_breakOnRealloc(A) 0 +#define Memento_getBlockNum(A) 0 +#define Memento_find(A) 0 +#define Memento_breakpoint() do {} while (0) +#define Memento_failAt(A) 0 +#define Memento_failThisEvent() 0 +#define Memento_listBlocks() do {} while (0) +#define Memento_listNewBlocks() do {} while (0) +#define Memento_setMax(A) 0 +#define Memento_stats() do {} while (0) +#define Memento_label(A,B) (A) #endif /* MEMENTO */ -- cgit v1.2.1