summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobin Watts <robin.watts@artifex.com>2012-04-26 15:11:18 +0100
committerRobin Watts <robin.watts@artifex.com>2012-04-26 15:21:10 +0100
commitdd09a0706ab09a54f5fbb05c63420c86375b45bf (patch)
tree893ad1e25bd9fed365c9742271de5760b2d39e63
parent012aef926d1e33cc64c32bf8e94ef92a299d73f9 (diff)
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.
-rw-r--r--gs/base/memento.c93
-rw-r--r--gs/base/memento.h36
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 */