1 /* Copyright (C) 2001-2012 Artifex Software, Inc.
4 This software is provided AS-IS with no warranty, either express or
7 This software is distributed under license and may not be copied,
8 modified or distributed except as expressly authorized under the terms
9 of the license contained in the file LICENSE in this distribution.
11 Refer to licensing information at http://www.artifex.com or contact
12 Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael,
13 CA 94903, U.S.A., +1(415)492-9861, for further information.
17 /* Inspired by Fortify by Simon P Bullen. */
20 /* Set the following if you're only looking for leaks, not memory overwrites
21 * to speed the operation */
22 /* #define MEMENTO_LEAKONLY */
24 #ifndef MEMENTO_STACKTRACE_METHOD
26 #define MEMENTO_STACKTRACE_METHOD 1
30 /* Don't keep blocks around if they'd mean losing more than a quarter of
32 #define MEMENTO_FREELIST_MAX_SINGLE_BLOCK (MEMENTO_FREELIST_MAX/4)
34 #define COMPILING_MEMENTO_C
36 #ifdef MEMENTO_GS_HACKS
37 /* For GS we include malloc_.h. Anyone else would just include memento.h */
43 void *memset(void *,int,size_t);
46 int atexit(void (*)(void));
53 #if defined(__linux__)
54 #define MEMENTO_HAS_FORK
55 #elif defined(__APPLE__) && defined(__MACH__)
56 #define MEMENTO_HAS_FORK
59 /* Define the underlying allocators, just in case */
60 void *MEMENTO_UNDERLYING_MALLOC(size_t);
61 void MEMENTO_UNDERLYING_FREE(void *);
62 void *MEMENTO_UNDERLYING_REALLOC(void *,size_t);
63 void *MEMENTO_UNDERLYING_CALLOC(size_t,size_t);
65 /* And some other standard functions we use. We don't include the header
66 * files, just in case they pull in unexpected others. */
67 int atoi(const char *);
68 char *getenv(const char *);
70 /* How far to search for pointers in each block when calculating nestings */
71 /* mupdf needs at least 34000ish (sizeof(fz_shade))/ */
72 #define MEMENTO_PTRSEARCH 65536
74 #ifndef MEMENTO_MAXPATTERN
75 #define MEMENTO_MAXPATTERN 0
80 #ifdef MEMENTO_GS_HACKS
84 #include "valgrind/memcheck.h"
86 #define VALGRIND_MAKE_MEM_NOACCESS(p,s) do { } while (0==1)
87 #define VALGRIND_MAKE_MEM_UNDEFINED(p,s) do { } while (0==1)
88 #define VALGRIND_MAKE_MEM_DEFINED(p,s) do { } while (0==1)
98 Memento_Flag_OldBlock = 1,
99 Memento_Flag_HasParent = 2,
100 Memento_Flag_BreakOnFree = 4,
101 Memento_Flag_BreakOnRealloc = 8
104 /* When we list leaked blocks at the end of execution, we search for pointers
105 * between blocks in order to be able to give a nice nested view.
106 * Unfortunately, if you have are running your own allocator (such as
107 * ghostscripts chunk allocator) you can often find that the header of the
108 * block always contains pointers to next or previous blocks. This tends to
109 * mean the nesting displayed is "uninteresting" at best :)
111 * As a hack to get around this, we have a define MEMENTO_SKIP_SEARCH that
112 * indicates how many bytes to skip over at the start of the chunk.
113 * This may cause us to miss true nestings, but such is life...
115 #ifndef MEMENTO_SEARCH_SKIP
116 #ifdef MEMENTO_GS_HACKS
117 #define MEMENTO_SEARCH_SKIP (2*sizeof(void *))
119 #define MEMENTO_SEARCH_SKIP 0
123 typedef struct Memento_BlkHeader Memento_BlkHeader;
125 struct Memento_BlkHeader
131 Memento_BlkHeader *next;
132 Memento_BlkHeader *parent; /* Only used while printing out nested list */
136 /* Entries for nesting display calculations */
137 Memento_BlkHeader *child;
138 Memento_BlkHeader *sibling;
140 char preblk[Memento_PreSize];
143 /* In future this could (should) be a smarter data structure, like, say,
144 * splay trees. For now, we use a list.
146 typedef struct Memento_Blocks
148 Memento_BlkHeader *head;
149 Memento_BlkHeader **tail;
152 /* And our global structure */
182 #define MEMENTO_EXTRASIZE (sizeof(Memento_BlkHeader) + Memento_PostSize)
184 /* Round up size S to the next multiple of N (where N is a power of 2) */
185 #define MEMENTO_ROUNDUP(S,N) ((S + N-1)&~(N-1))
187 #define MEMBLK_SIZE(s) MEMENTO_ROUNDUP(s + MEMENTO_EXTRASIZE, MEMENTO_MAXALIGN)
189 #define MEMBLK_FROMBLK(B) (&((Memento_BlkHeader*)(void *)(B))[-1])
190 #define MEMBLK_TOBLK(B) ((void*)(&((Memento_BlkHeader*)(void*)(B))[1]))
191 #define MEMBLK_POSTPTR(B) \
192 (&((char *)(void *)(B))[(B)->rawsize + sizeof(Memento_BlkHeader)])
194 void Memento_breakpoint(void)
196 /* A handy externally visible function for breakpointing */
197 #if 0 /* Enable this to force automatic breakpointing */
206 static void Memento_addBlockHead(Memento_Blocks *blks,
207 Memento_BlkHeader *b,
210 if (blks->tail == &blks->head) {
211 /* Adding into an empty list, means the tail changes too */
212 blks->tail = &b->next;
214 b->next = blks->head;
216 #ifndef MEMENTO_LEAKONLY
217 memset(b->preblk, MEMENTO_PREFILL, Memento_PreSize);
218 memset(MEMBLK_POSTPTR(b), MEMENTO_POSTFILL, Memento_PostSize);
220 VALGRIND_MAKE_MEM_NOACCESS(MEMBLK_POSTPTR(b), Memento_PostSize);
221 if (type == 0) { /* malloc */
222 VALGRIND_MAKE_MEM_UNDEFINED(MEMBLK_TOBLK(b), b->rawsize);
223 } else if (type == 1) { /* free */
224 VALGRIND_MAKE_MEM_NOACCESS(MEMBLK_TOBLK(b), b->rawsize);
226 VALGRIND_MAKE_MEM_NOACCESS(b, sizeof(Memento_BlkHeader));
229 static void Memento_addBlockTail(Memento_Blocks *blks,
230 Memento_BlkHeader *b,
233 VALGRIND_MAKE_MEM_DEFINED(blks->tail, sizeof(Memento_BlkHeader *));
235 blks->tail = &b->next;
237 VALGRIND_MAKE_MEM_NOACCESS(blks->tail, sizeof(Memento_BlkHeader *));
238 #ifndef MEMENTO_LEAKONLY
239 memset(b->preblk, MEMENTO_PREFILL, Memento_PreSize);
240 memset(MEMBLK_POSTPTR(b), MEMENTO_POSTFILL, Memento_PostSize);
242 VALGRIND_MAKE_MEM_NOACCESS(MEMBLK_POSTPTR(b), Memento_PostSize);
243 if (type == 0) { /* malloc */
244 VALGRIND_MAKE_MEM_UNDEFINED(MEMBLK_TOBLK(b), b->rawsize);
245 } else if (type == 1) { /* free */
246 VALGRIND_MAKE_MEM_NOACCESS(MEMBLK_TOBLK(b), b->rawsize);
248 VALGRIND_MAKE_MEM_NOACCESS(b, sizeof(Memento_BlkHeader));
251 typedef struct BlkCheckData {
259 static int Memento_Internal_checkAllocedBlock(Memento_BlkHeader *b, void *arg)
261 #ifndef MEMENTO_LEAKONLY
265 BlkCheckData *data = (BlkCheckData *)arg;
270 corrupt |= (*p++ ^ (char)MEMENTO_PREFILL);
273 data->preCorrupt = 1;
275 p = MEMBLK_POSTPTR(b);
278 corrupt |= (*p++ ^ (char)MEMENTO_POSTFILL);
281 data->postCorrupt = 1;
283 if ((data->freeCorrupt | data->preCorrupt | data->postCorrupt) == 0) {
284 b->lastCheckedOK = globals.sequence;
291 static int Memento_Internal_checkFreedBlock(Memento_BlkHeader *b, void *arg)
293 #ifndef MEMENTO_LEAKONLY
296 BlkCheckData *data = (BlkCheckData *)arg;
300 /* Attempt to speed this up by checking an (aligned) int at a time */
302 if (((size_t)p) & 1) {
303 if (*p++ != (char)MEMENTO_FREEFILL)
309 if ((i >= 2) && (((size_t)p) & 2)) {
310 if (*(short *)p != (short)(MEMENTO_FREEFILL | (MEMENTO_FREEFILL<<8)))
319 if (*(int *)p != (MEMENTO_FREEFILL |
320 (MEMENTO_FREEFILL<<8) |
321 (MEMENTO_FREEFILL<<16) |
322 (MEMENTO_FREEFILL<<24)))
328 if ((i >= 2) && (((size_t)p) & 2)) {
329 if (*(short *)p != (short)(MEMENTO_FREEFILL | (MEMENTO_FREEFILL<<8)))
336 if (*p++ != (char)MEMENTO_FREEFILL)
342 data->freeCorrupt = 1;
343 data->index = b->rawsize-i;
345 return Memento_Internal_checkAllocedBlock(b, arg);
351 static void Memento_removeBlock(Memento_Blocks *blks,
352 Memento_BlkHeader *b)
354 Memento_BlkHeader *head = blks->head;
355 Memento_BlkHeader *prev = NULL;
356 while ((head) && (head != b)) {
357 VALGRIND_MAKE_MEM_DEFINED(head, sizeof(*head));
360 VALGRIND_MAKE_MEM_NOACCESS(prev, sizeof(*prev));
363 /* FAIL! Will have been reported to user earlier, so just exit. */
366 VALGRIND_MAKE_MEM_DEFINED(blks->tail, sizeof(*blks->tail));
367 if (*blks->tail == head) {
368 /* Removing the tail of the list */
370 /* Which is also the head */
371 blks->tail = &blks->head;
373 /* Which isn't the head */
374 blks->tail = &prev->next;
378 /* Removing from the head of the list */
379 VALGRIND_MAKE_MEM_DEFINED(head, sizeof(*head));
380 blks->head = head->next;
381 VALGRIND_MAKE_MEM_NOACCESS(head, sizeof(*head));
383 /* Removing from not-the-head */
384 VALGRIND_MAKE_MEM_DEFINED(head, sizeof(*head));
385 VALGRIND_MAKE_MEM_DEFINED(prev, sizeof(*prev));
386 prev->next = head->next;
387 VALGRIND_MAKE_MEM_NOACCESS(head, sizeof(*head));
388 VALGRIND_MAKE_MEM_NOACCESS(prev, sizeof(*prev));
392 static int Memento_Internal_makeSpace(size_t space)
394 /* If too big, it can never go on the freelist */
395 if (space > MEMENTO_FREELIST_MAX_SINGLE_BLOCK)
397 /* Pretend we added it on. */
398 globals.freeListSize += space;
399 /* Ditch blocks until it fits within our limit */
400 while (globals.freeListSize > MEMENTO_FREELIST_MAX) {
401 Memento_BlkHeader *head = globals.free.head;
402 VALGRIND_MAKE_MEM_DEFINED(head, sizeof(*head));
403 globals.free.head = head->next;
404 globals.freeListSize -= MEMBLK_SIZE(head->rawsize);
405 MEMENTO_UNDERLYING_FREE(head);
407 /* Make sure we haven't just completely emptied the free list */
408 /* (This should never happen, but belt and braces... */
409 if (globals.free.head == NULL)
410 globals.free.tail = &globals.free.head;
414 static int Memento_appBlocks(Memento_Blocks *blks,
415 int (*app)(Memento_BlkHeader *,
419 Memento_BlkHeader *head = blks->head;
420 Memento_BlkHeader *next;
423 VALGRIND_MAKE_MEM_DEFINED(head, sizeof(Memento_BlkHeader));
424 VALGRIND_MAKE_MEM_DEFINED(MEMBLK_TOBLK(head),
425 head->rawsize + Memento_PostSize);
426 result = app(head, arg);
428 VALGRIND_MAKE_MEM_NOACCESS(MEMBLK_POSTPTR(head), Memento_PostSize);
429 VALGRIND_MAKE_MEM_NOACCESS(head, sizeof(Memento_BlkHeader));
437 static int Memento_appBlock(Memento_Blocks *blks,
438 int (*app)(Memento_BlkHeader *,
441 Memento_BlkHeader *b)
443 Memento_BlkHeader *head = blks->head;
444 Memento_BlkHeader *next;
446 while (head && head != b) {
447 VALGRIND_MAKE_MEM_DEFINED(head, sizeof(Memento_BlkHeader));
449 VALGRIND_MAKE_MEM_NOACCESS(MEMBLK_POSTPTR(head), Memento_PostSize);
453 VALGRIND_MAKE_MEM_DEFINED(head, sizeof(Memento_BlkHeader));
454 VALGRIND_MAKE_MEM_DEFINED(MEMBLK_TOBLK(head),
455 head->rawsize + Memento_PostSize);
456 result = app(head, arg);
457 VALGRIND_MAKE_MEM_NOACCESS(MEMBLK_POSTPTR(head), Memento_PostSize);
458 VALGRIND_MAKE_MEM_NOACCESS(head, sizeof(Memento_BlkHeader));
464 static void showBlock(Memento_BlkHeader *b, int space)
466 fprintf(stderr, "0x%p:(size=%d,num=%d)",
467 MEMBLK_TOBLK(b), (int)b->rawsize, b->sequence);
469 fprintf(stderr, "%c(%s)", space, b->label);
472 static void blockDisplay(Memento_BlkHeader *b, int n)
481 fprintf(stderr, "%s", &" "[32-i]);
484 fprintf(stderr, "\n");
487 static int Memento_listBlock(Memento_BlkHeader *b,
490 int *counts = (int *)arg;
493 counts[1]+= b->rawsize;
497 static void doNestedDisplay(Memento_BlkHeader *b,
500 blockDisplay(b, depth);
501 for (b = b->child; b; b = b->sibling)
502 doNestedDisplay(b, depth+1);
505 static int ptrcmp(const void *a_, const void *b_)
507 const char **a = (const char **)a_;
508 const char **b = (const char **)b_;
513 int Memento_listBlocksNested(void)
516 Memento_BlkHeader *b;
517 void **blocks, *minptr, *maxptr;
520 /* Count the blocks */
523 for (b = globals.used.head; b; b = b->next) {
528 /* Make our block list */
529 blocks = MEMENTO_UNDERLYING_MALLOC(sizeof(void *) * count);
533 /* Populate our block list */
534 b = globals.used.head;
535 minptr = maxptr = MEMBLK_TOBLK(b);
537 for (i = 0; b; b = b->next, i++) {
538 void *p = MEMBLK_TOBLK(b);
545 b->flags &= ~Memento_Flag_HasParent;
550 qsort(blocks, count, sizeof(void *), ptrcmp);
552 /* Now, calculate tree */
553 for (b = globals.used.head; b; b = b->next) {
554 char *p = MEMBLK_TOBLK(b);
555 int end = (b->rawsize < MEMENTO_PTRSEARCH ? b->rawsize : MEMENTO_PTRSEARCH);
556 for (i = MEMENTO_SEARCH_SKIP; i < end; i += sizeof(void *)) {
557 void *q = *(void **)(&p[i]);
560 /* Do trivial checks on pointer */
561 if ((mask & (int)q) != mask || q < minptr || q > maxptr)
564 /* Search for pointer */
565 r = bsearch(&q, blocks, count, sizeof(void *), ptrcmp);
568 Memento_BlkHeader *child = MEMBLK_FROMBLK(*r);
569 Memento_BlkHeader *parent;
571 /* We're assuming tree structure, not graph - ignore second
572 * and subsequent pointers. */
573 if (child->parent != NULL)
575 if (child->flags & Memento_Flag_HasParent)
578 /* We're also assuming acyclicness here. If this is one of
579 * our parents, ignore it. */
581 while (parent != NULL && parent != child)
582 parent = parent->parent;
586 child->sibling = b->child;
589 child->flags |= Memento_Flag_HasParent;
594 /* Now display with nesting */
595 for (b = globals.used.head; b; b = b->next) {
596 if ((b->flags & Memento_Flag_HasParent) == 0)
597 doNestedDisplay(b, 0);
599 fprintf(stderr, " Total number of blocks = %d\n", count);
600 fprintf(stderr, " Total size of blocks = %d\n", size);
602 MEMENTO_UNDERLYING_FREE(blocks);
606 void Memento_listBlocks(void)
608 fprintf(stderr, "Allocated blocks:\n");
609 if (Memento_listBlocksNested())
614 Memento_appBlocks(&globals.used, Memento_listBlock, &counts[0]);
615 fprintf(stderr, " Total number of blocks = %d\n", counts[0]);
616 fprintf(stderr, " Total size of blocks = %d\n", counts[1]);
620 static int Memento_listNewBlock(Memento_BlkHeader *b,
623 if (b->flags & Memento_Flag_OldBlock)
625 b->flags |= Memento_Flag_OldBlock;
626 return Memento_listBlock(b, arg);
629 void Memento_listNewBlocks(void) {
633 fprintf(stderr, "Blocks allocated and still extant since last list:\n");
634 Memento_appBlocks(&globals.used, Memento_listNewBlock, &counts[0]);
635 fprintf(stderr, " Total number of blocks = %d\n", counts[0]);
636 fprintf(stderr, " Total size of blocks = %d\n", counts[1]);
639 static void Memento_endStats(void)
641 fprintf(stderr, "Total memory malloced = %u bytes\n", (unsigned int)globals.totalAlloc);
642 fprintf(stderr, "Peak memory malloced = %u bytes\n", (unsigned int)globals.peakAlloc);
643 fprintf(stderr, "%u mallocs, %u frees, %u reallocs\n", (unsigned int)globals.numMallocs,
644 (unsigned int)globals.numFrees, (unsigned int)globals.numReallocs);
645 fprintf(stderr, "Average allocation size %u bytes\n", (unsigned int)
646 (globals.numMallocs != 0 ? globals.totalAlloc/globals.numMallocs: 0));
649 void Memento_stats(void)
651 fprintf(stderr, "Current memory malloced = %u bytes\n", (unsigned int)globals.alloc);
655 static void Memento_fin(void)
657 Memento_checkAllMemory();
659 if (globals.used.head != NULL) {
660 Memento_listBlocks();
661 Memento_breakpoint();
664 fprintf(stderr, "Memory dumped on SEGV while squeezing @ %d\n", globals.failAt);
665 } else if (globals.squeezing) {
666 if (globals.pattern == 0)
667 fprintf(stderr, "Memory squeezing @ %d complete\n", globals.squeezeAt);
669 fprintf(stderr, "Memory squeezing @ %d (%d) complete\n", globals.squeezeAt, globals.pattern);
673 fprintf(stderr, "MEMENTO_FAILAT=%d\n", globals.failAt);
674 fprintf(stderr, "MEMENTO_PATTERN=%d\n", globals.pattern);
676 if (globals.nextFailAt != 0)
678 fprintf(stderr, "MEMENTO_NEXTFAILAT=%d\n", globals.nextFailAt);
679 fprintf(stderr, "MEMENTO_NEXTPATTERN=%d\n", globals.nextPattern);
683 static void Memento_inited(void)
685 /* A good place for a breakpoint */
688 static void Memento_init(void)
691 memset(&globals, 0, sizeof(globals));
693 globals.used.head = NULL;
694 globals.used.tail = &globals.used.head;
695 globals.free.head = NULL;
696 globals.free.tail = &globals.free.head;
697 globals.sequence = 0;
698 globals.countdown = 1024;
700 env = getenv("MEMENTO_FAILAT");
701 globals.failAt = (env ? atoi(env) : 0);
703 env = getenv("MEMENTO_PARANOIA");
704 globals.paranoia = (env ? atoi(env) : 0);
705 if (globals.paranoia == 0)
706 globals.paranoia = 1024;
708 env = getenv("MEMENTO_PARANOIDAT");
709 globals.paranoidAt = (env ? atoi(env) : 0);
711 env = getenv("MEMENTO_SQUEEZEAT");
712 globals.squeezeAt = (env ? atoi(env) : 0);
714 env = getenv("MEMENTO_PATTERN");
715 globals.pattern = (env ? atoi(env) : 0);
717 env = getenv("MEMENTO_MAXMEMORY");
718 globals.maxMemory = (env ? atoi(env) : 0);
725 #ifdef MEMENTO_HAS_FORK
727 #include <sys/wait.h>
728 #ifdef MEMENTO_STACKTRACE_METHOD
729 #if MEMENTO_STACKTRACE_METHOD == 1
734 /* FIXME: Find some portable way of getting this */
735 /* MacOSX has 10240, Ubuntu seems to have 256 */
736 #define OPEN_MAX 10240
738 /* stashed_map[j] = i means that filedescriptor i-1 was duplicated to j */
739 int stashed_map[OPEN_MAX];
741 extern size_t backtrace(void **, int);
742 extern void backtrace_symbols_fd(void **, size_t, int);
744 static void Memento_signal(void)
746 fprintf(stderr, "SEGV after Memory squeezing @ %d\n", globals.squeezeAt);
748 #ifdef MEMENTO_STACKTRACE_METHOD
749 #if MEMENTO_STACKTRACE_METHOD == 1
754 size = backtrace(array, 100);
755 fprintf(stderr, "------------------------------------------------------------------------\n");
756 fprintf(stderr, "Backtrace:\n");
757 backtrace_symbols_fd(array, size, 2);
758 fprintf(stderr, "------------------------------------------------------------------------\n");
766 static int squeeze(void)
771 if (globals.patternBit < 0)
773 if (globals.squeezing && globals.patternBit >= MEMENTO_MAXPATTERN)
776 if (globals.patternBit == 0)
777 globals.squeezeAt = globals.sequence;
779 if (!globals.squeezing) {
780 fprintf(stderr, "Memory squeezing @ %d\n", globals.squeezeAt);
782 fprintf(stderr, "Memory squeezing @ %d (%x,%x)\n", globals.squeezeAt, globals.pattern, globals.patternBit);
784 /* When we fork below, the child is going to snaffle all our file pointers
785 * and potentially corrupt them. Let's make copies of all of them before
786 * we fork, so we can restore them when we restart. */
787 for (i = 0; i < OPEN_MAX; i++) {
788 if (stashed_map[i] == 0) {
790 stashed_map[j] = i+1;
797 signal(SIGSEGV, Memento_signal);
798 /* In the child, we always fail the next allocation. */
799 if (globals.patternBit == 0) {
800 globals.patternBit = 1;
802 globals.patternBit <<= 1;
803 globals.squeezing = 1;
807 /* In the parent if we hit another allocation, pass it (and record the
808 * fact we passed it in the pattern. */
809 globals.pattern |= globals.patternBit;
810 globals.patternBit <<= 1;
812 /* Wait for pid to finish */
813 waitpid(pid, &status, 0);
816 fprintf(stderr, "Child status=%d\n", status);
819 /* Put the files back */
820 for (i = 0; i < OPEN_MAX; i++) {
821 if (stashed_map[i] != 0) {
822 dup2(i, stashed_map[i]-1);
833 static void Memento_signal(void)
836 /* If we just return from this function the SEGV will be unhandled, and
837 * we'll launch into whatever JIT debugging system the OS provides. At
838 * least output something useful first. If MEMENTO_NOJIT is set, then
839 * just exit to avoid the JIT (and get the usual atexit handling). */
840 if (getenv("MEMENTO_NOJIT"))
848 fprintf(stderr, "Memento memory squeezing disabled as no fork!\n");
853 static void Memento_startFailing(void)
855 if (!globals.failing) {
856 fprintf(stderr, "Starting to fail...\n");
859 globals.failAt = globals.sequence;
860 globals.nextFailAt = globals.sequence+1;
862 globals.patternBit = 0;
863 signal(SIGSEGV, Memento_signal);
864 signal(SIGABRT, Memento_signal);
865 Memento_breakpoint();
869 static void Memento_event(void)
872 if ((globals.sequence >= globals.paranoidAt) && (globals.paranoidAt != 0)) {
873 globals.paranoia = 1;
874 globals.countdown = 1;
876 if (--globals.countdown == 0) {
877 Memento_checkAllMemory();
878 globals.countdown = globals.paranoia;
881 if (globals.sequence == globals.breakAt) {
882 fprintf(stderr, "Breaking at event %d\n", globals.breakAt);
883 Memento_breakpoint();
887 int Memento_breakAt(int event)
889 globals.breakAt = event;
893 void *Memento_label(void *ptr, const char *label)
895 Memento_BlkHeader *block;
899 block = MEMBLK_FROMBLK(ptr);
900 block->label = label;
904 int Memento_failThisEvent(void)
913 if ((globals.sequence >= globals.failAt) && (globals.failAt != 0))
914 Memento_startFailing();
915 if ((globals.sequence >= globals.squeezeAt) && (globals.squeezeAt != 0)) {
919 if (!globals.failing)
921 failThisOne = ((globals.patternBit & globals.pattern) == 0);
922 /* If we are failing, and we've reached the end of the pattern and we've
923 * still got bits available in the pattern word, and we haven't already
924 * set a nextPattern, then extend the pattern. */
925 if (globals.failing &&
926 ((~(globals.patternBit-1) & globals.pattern) == 0) &&
927 (globals.patternBit != 0) &&
928 globals.nextPattern == 0)
930 /* We'll fail this one, and set the 'next' one to pass it. */
931 globals.nextFailAt = globals.failAt;
932 globals.nextPattern = globals.pattern | globals.patternBit;
934 globals.patternBit = (globals.patternBit ? globals.patternBit << 1 : 1);
939 void *Memento_malloc(size_t s)
941 Memento_BlkHeader *memblk;
942 size_t smem = MEMBLK_SIZE(s);
944 if (Memento_failThisEvent())
950 globals.numMallocs++;
952 if (globals.maxMemory != 0 && globals.alloc + s > globals.maxMemory)
955 memblk = MEMENTO_UNDERLYING_MALLOC(smem);
960 globals.totalAlloc += s;
961 if (globals.peakAlloc < globals.alloc)
962 globals.peakAlloc = globals.alloc;
963 #ifndef MEMENTO_LEAKONLY
964 memset(MEMBLK_TOBLK(memblk), MEMENTO_ALLOCFILL, s);
967 memblk->sequence = globals.sequence;
968 memblk->lastCheckedOK = memblk->sequence;
971 memblk->child = NULL;
972 memblk->sibling = NULL;
973 Memento_addBlockHead(&globals.used, memblk, 0);
974 return MEMBLK_TOBLK(memblk);
977 void *Memento_calloc(size_t n, size_t s)
979 void *block = Memento_malloc(n*s);
982 memset(block, 0, n*s);
986 static int checkBlock(Memento_BlkHeader *memblk, const char *action)
988 #ifndef MEMENTO_LEAKONLY
991 memset(&data, 0, sizeof(data));
992 Memento_appBlock(&globals.used, Memento_Internal_checkAllocedBlock,
996 fprintf(stderr, "Attempt to %s block ", action);
997 showBlock(memblk, 32);
998 Memento_breakpoint();
1000 } else if (data.preCorrupt || data.postCorrupt) {
1001 fprintf(stderr, "Block ");
1002 showBlock(memblk, ' ');
1003 fprintf(stderr, " found to be corrupted on %s!\n", action);
1004 if (data.preCorrupt) {
1005 fprintf(stderr, "Preguard corrupted\n");
1007 if (data.postCorrupt) {
1008 fprintf(stderr, "Postguard corrupted\n");
1010 fprintf(stderr, "Block last checked OK at allocation %d. Now %d.\n",
1011 memblk->lastCheckedOK, globals.sequence);
1012 Memento_breakpoint();
1019 void Memento_free(void *blk)
1021 Memento_BlkHeader *memblk;
1023 if (!globals.inited)
1031 memblk = MEMBLK_FROMBLK(blk);
1032 VALGRIND_MAKE_MEM_DEFINED(memblk, sizeof(*memblk));
1033 if (checkBlock(memblk, "free"))
1036 if (memblk->flags & Memento_Flag_BreakOnFree)
1037 Memento_breakpoint();
1039 VALGRIND_MAKE_MEM_DEFINED(memblk, sizeof(*memblk));
1040 globals.alloc -= memblk->rawsize;
1043 Memento_removeBlock(&globals.used, memblk);
1045 VALGRIND_MAKE_MEM_DEFINED(memblk, sizeof(*memblk));
1046 if (Memento_Internal_makeSpace(MEMBLK_SIZE(memblk->rawsize))) {
1047 VALGRIND_MAKE_MEM_DEFINED(memblk, sizeof(*memblk));
1048 VALGRIND_MAKE_MEM_DEFINED(MEMBLK_TOBLK(memblk),
1049 memblk->rawsize + Memento_PostSize);
1050 #ifndef MEMENTO_LEAKONLY
1051 memset(MEMBLK_TOBLK(memblk), MEMENTO_FREEFILL, memblk->rawsize);
1053 Memento_addBlockTail(&globals.free, memblk, 1);
1055 MEMENTO_UNDERLYING_FREE(memblk);
1059 void *Memento_realloc(void *blk, size_t newsize)
1061 Memento_BlkHeader *memblk, *newmemblk;
1066 return Memento_malloc(newsize);
1072 if (Memento_failThisEvent())
1075 memblk = MEMBLK_FROMBLK(blk);
1076 if (checkBlock(memblk, "realloc"))
1079 if (memblk->flags & Memento_Flag_BreakOnRealloc)
1080 Memento_breakpoint();
1082 if (globals.maxMemory != 0 && globals.alloc - memblk->rawsize + newsize > globals.maxMemory)
1085 newsizemem = MEMBLK_SIZE(newsize);
1086 Memento_removeBlock(&globals.used, memblk);
1087 flags = memblk->flags;
1088 newmemblk = MEMENTO_UNDERLYING_REALLOC(memblk, newsizemem);
1089 if (newmemblk == NULL)
1091 Memento_addBlockHead(&globals.used, memblk, 2);
1094 globals.numReallocs++;
1095 globals.totalAlloc += newsize;
1096 globals.alloc -= newmemblk->rawsize;
1097 globals.alloc += newsize;
1098 if (globals.peakAlloc < globals.alloc)
1099 globals.peakAlloc = globals.alloc;
1100 newmemblk->flags = flags;
1101 if (newmemblk->rawsize < newsize) {
1102 char *newbytes = ((char *)MEMBLK_TOBLK(newmemblk))+newmemblk->rawsize;
1103 #ifndef MEMENTO_LEAKONLY
1104 memset(newbytes, MEMENTO_ALLOCFILL, newsize - newmemblk->rawsize);
1106 VALGRIND_MAKE_MEM_UNDEFINED(newbytes, newsize - newmemblk->rawsize);
1108 newmemblk->rawsize = newsize;
1109 #ifndef MEMENTO_LEAKONLY
1110 memset(newmemblk->preblk, MEMENTO_PREFILL, Memento_PreSize);
1111 memset(MEMBLK_POSTPTR(newmemblk), MEMENTO_POSTFILL, Memento_PostSize);
1113 Memento_addBlockHead(&globals.used, newmemblk, 2);
1114 return MEMBLK_TOBLK(newmemblk);
1117 int Memento_checkBlock(void *blk)
1119 Memento_BlkHeader *memblk;
1123 memblk = MEMBLK_FROMBLK(blk);
1124 return checkBlock(memblk, "check");
1127 static int Memento_Internal_checkAllAlloced(Memento_BlkHeader *memblk, void *arg)
1129 BlkCheckData *data = (BlkCheckData *)arg;
1131 Memento_Internal_checkAllocedBlock(memblk, data);
1132 if (data->preCorrupt || data->postCorrupt) {
1133 if ((data->found & 2) == 0) {
1134 fprintf(stderr, "Allocated blocks:\n");
1137 fprintf(stderr, " Block ");
1138 showBlock(memblk, ' ');
1139 if (data->preCorrupt) {
1140 fprintf(stderr, " Preguard ");
1142 if (data->postCorrupt) {
1143 fprintf(stderr, "%s Postguard ",
1144 (data->preCorrupt ? "&" : ""));
1146 fprintf(stderr, "corrupted.\n "
1147 "Block last checked OK at allocation %d. Now %d.\n",
1148 memblk->lastCheckedOK, globals.sequence);
1149 data->preCorrupt = 0;
1150 data->postCorrupt = 0;
1151 data->freeCorrupt = 0;
1154 memblk->lastCheckedOK = globals.sequence;
1158 static int Memento_Internal_checkAllFreed(Memento_BlkHeader *memblk, void *arg)
1160 BlkCheckData *data = (BlkCheckData *)arg;
1162 Memento_Internal_checkFreedBlock(memblk, data);
1163 if (data->preCorrupt || data->postCorrupt || data->freeCorrupt) {
1164 if ((data->found & 4) == 0) {
1165 fprintf(stderr, "Freed blocks:\n");
1168 fprintf(stderr, " ");
1169 showBlock(memblk, ' ');
1170 if (data->freeCorrupt) {
1171 fprintf(stderr, " index %d (address 0x%p) onwards", data->index,
1172 &((char *)MEMBLK_TOBLK(memblk))[data->index]);
1173 if (data->preCorrupt) {
1174 fprintf(stderr, "+ preguard");
1176 if (data->postCorrupt) {
1177 fprintf(stderr, "+ postguard");
1180 if (data->preCorrupt) {
1181 fprintf(stderr, " preguard");
1183 if (data->postCorrupt) {
1184 fprintf(stderr, "%s Postguard",
1185 (data->preCorrupt ? "+" : ""));
1188 fprintf(stderr, " corrupted.\n"
1189 " Block last checked OK at allocation %d. Now %d.\n",
1190 memblk->lastCheckedOK, globals.sequence);
1191 data->preCorrupt = 0;
1192 data->postCorrupt = 0;
1193 data->freeCorrupt = 0;
1196 memblk->lastCheckedOK = globals.sequence;
1200 int Memento_checkAllMemory(void)
1202 #ifndef MEMENTO_LEAKONLY
1205 memset(&data, 0, sizeof(data));
1206 Memento_appBlocks(&globals.used, Memento_Internal_checkAllAlloced, &data);
1207 Memento_appBlocks(&globals.free, Memento_Internal_checkAllFreed, &data);
1208 if (data.found & 6) {
1209 Memento_breakpoint();
1216 int Memento_setParanoia(int i)
1218 globals.paranoia = i;
1219 globals.countdown = globals.paranoia;
1223 int Memento_paranoidAt(int i)
1225 globals.paranoidAt = i;
1229 int Memento_getBlockNum(void *b)
1231 Memento_BlkHeader *memblk;
1234 memblk = MEMBLK_FROMBLK(b);
1235 return (memblk->sequence);
1238 int Memento_check(void)
1242 fprintf(stderr, "Checking memory\n");
1243 result = Memento_checkAllMemory();
1244 fprintf(stderr, "Memory checked!\n");
1248 typedef struct findBlkData {
1250 Memento_BlkHeader *blk;
1254 static int Memento_containsAddr(Memento_BlkHeader *b,
1257 findBlkData *data = (findBlkData *)arg;
1258 char *blkend = &((char *)MEMBLK_TOBLK(b))[b->rawsize];
1259 if ((MEMBLK_TOBLK(b) <= data->addr) &&
1260 ((void *)blkend > data->addr)) {
1265 if (((void *)b <= data->addr) &&
1266 (MEMBLK_TOBLK(b) > data->addr)) {
1271 if (((void *)blkend <= data->addr) &&
1272 ((void *)(blkend + Memento_PostSize) > data->addr)) {
1280 int Memento_find(void *a)
1287 Memento_appBlocks(&globals.used, Memento_containsAddr, &data);
1288 if (data.blk != NULL) {
1289 fprintf(stderr, "Address 0x%p is in %sallocated block ",
1291 (data.flags == 1 ? "" : (data.flags == 2 ?
1292 "preguard of " : "postguard of ")));
1293 showBlock(data.blk, ' ');
1294 fprintf(stderr, "\n");
1295 return data.blk->sequence;
1299 Memento_appBlocks(&globals.free, Memento_containsAddr, &data);
1300 if (data.blk != NULL) {
1301 fprintf(stderr, "Address 0x%p is in %sfreed block ",
1303 (data.flags == 1 ? "" : (data.flags == 2 ?
1304 "preguard of " : "postguard of ")));
1305 showBlock(data.blk, ' ');
1306 fprintf(stderr, "\n");
1307 return data.blk->sequence;
1312 void Memento_breakOnFree(void *a)
1319 Memento_appBlocks(&globals.used, Memento_containsAddr, &data);
1320 if (data.blk != NULL) {
1321 fprintf(stderr, "Will stop when address 0x%p (in %sallocated block ",
1323 (data.flags == 1 ? "" : (data.flags == 2 ?
1324 "preguard of " : "postguard of ")));
1325 showBlock(data.blk, ' ');
1326 fprintf(stderr, ") is freed\n");
1327 data.blk->flags |= Memento_Flag_BreakOnFree;
1332 Memento_appBlocks(&globals.free, Memento_containsAddr, &data);
1333 if (data.blk != NULL) {
1334 fprintf(stderr, "Can't stop on free; address 0x%p is in %sfreed block ",
1336 (data.flags == 1 ? "" : (data.flags == 2 ?
1337 "preguard of " : "postguard of ")));
1338 showBlock(data.blk, ' ');
1339 fprintf(stderr, "\n");
1342 fprintf(stderr, "Can't stop on free; address 0x%p is not in a known block.\n", a);
1345 void Memento_breakOnRealloc(void *a)
1352 Memento_appBlocks(&globals.used, Memento_containsAddr, &data);
1353 if (data.blk != NULL) {
1354 fprintf(stderr, "Will stop when address 0x%p (in %sallocated block ",
1356 (data.flags == 1 ? "" : (data.flags == 2 ?
1357 "preguard of " : "postguard of ")));
1358 showBlock(data.blk, ' ');
1359 fprintf(stderr, ") is freed (or realloced)\n");
1360 data.blk->flags |= Memento_Flag_BreakOnFree | Memento_Flag_BreakOnRealloc;
1365 Memento_appBlocks(&globals.free, Memento_containsAddr, &data);
1366 if (data.blk != NULL) {
1367 fprintf(stderr, "Can't stop on free/realloc; address 0x%p is in %sfreed block ",
1369 (data.flags == 1 ? "" : (data.flags == 2 ?
1370 "preguard of " : "postguard of ")));
1371 showBlock(data.blk, ' ');
1372 fprintf(stderr, "\n");
1375 fprintf(stderr, "Can't stop on free/realloc; address 0x%p is not in a known block.\n", a);
1378 int Memento_failAt(int i)
1381 if ((globals.sequence > globals.failAt) &&
1382 (globals.failing != 0))
1383 Memento_startFailing();
1387 size_t Memento_setMax(size_t max)
1389 globals.maxMemory = max;
1395 /* Just in case anyone has left some debugging code in... */
1396 void (Memento_breakpoint)(void)
1400 int (Memento_checkBlock)(void *b)
1405 int (Memento_checkAllMemory)(void)
1410 int (Memento_check)(void)
1415 int (Memento_setParanoia)(int i)
1420 int (Memento_paranoidAt)(int i)
1425 int (Memento_breakAt)(int i)
1430 int (Memento_getBlockNum)(void *i)
1435 int (Memento_find)(void *a)
1440 int (Memento_failAt)(int i)
1445 void (Memento_breakOnFree)(void *a)
1449 void (Memento_breakOnRealloc)(void *a)
1453 #undef Memento_malloc
1455 #undef Memento_realloc
1456 #undef Memento_calloc
1458 void *Memento_malloc(size_t size)
1460 return MEMENTO_UNDERLYING_MALLOC(size);
1463 void Memento_free(void *b)
1465 MEMENTO_UNDERLYING_FREE(b);
1468 void *Memento_realloc(void *b, size_t s)
1470 return MEMENTO_UNDERLYING_REALLOC(b, s);
1473 void *Memento_calloc(size_t n, size_t s)
1475 return MEMENTO_UNDERLYING_CALLOC(n, s);
1478 void (Memento_listBlocks)(void)
1482 void (Memento_listNewBlocks)(void)
1486 size_t (Memento_setMax)(size_t max)
1491 void (Memento_stats)(void)
1495 void *(Memento_label)(void *ptr, const char *label)