1 /* Copyright (C) 2001-2012 Artifex Software, Inc.
2    All Rights Reserved.
3 
4    This software is provided AS-IS with no warranty, either express or
5    implied.
6 
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.
10 
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.
14 */
15 
16 
17 /* Inspired by Fortify by Simon P Bullen. */
18 
19 
20 /* Set the following if you're only looking for leaks, not memory overwrites
21  * to speed the operation */
22 /* #define MEMENTO_LEAKONLY */
23 
24 #ifndef MEMENTO_STACKTRACE_METHOD
25 #ifdef __GNUC__
26 #define MEMENTO_STACKTRACE_METHOD 1
27 #endif
28 #endif
29 
30 /* Don't keep blocks around if they'd mean losing more than a quarter of
31  * the freelist. */
32 #define MEMENTO_FREELIST_MAX_SINGLE_BLOCK (MEMENTO_FREELIST_MAX/4)
33 
34 #define COMPILING_MEMENTO_C
35 
36 /* We have some GS specific tweaks; more for the GS build environment than
37  * anything else. */
38 #define MEMENTO_GS_HACKS
39 
40 #ifdef MEMENTO_GS_HACKS
41 /* For GS we include malloc_.h. Anyone else would just include memento.h */
42 #include "malloc_.h"
43 #ifdef __MACH__
44 #include <string.h>
45 #else
46 void *memset(void *,int,size_t);
47 #endif
48 int atexit(void (*)(void));
49 #else
50 #include "memento.h"
51 #include <stdio.h>
52 #include <stdlib.h>
53 #endif
54 
55 #if defined(__linux__)
56 #define MEMENTO_HAS_FORK
57 #elif defined(__APPLE__) && defined(__MACH__)
58 #define MEMENTO_HAS_FORK
59 #endif
60 
61 /* Define the underlying allocators, just in case */
62 void *MEMENTO_UNDERLYING_MALLOC(size_t);
63 void MEMENTO_UNDERLYING_FREE(void *);
64 void *MEMENTO_UNDERLYING_REALLOC(void *,size_t);
65 void *MEMENTO_UNDERLYING_CALLOC(size_t,size_t);
66 
67 /* And some other standard functions we use. We don't include the header
68  * files, just in case they pull in unexpected others. */
69 int atoi(const char *);
70 char *getenv(const char *);
71 
72 /* How far to search for pointers in each block when calculating nestings */
73 /* mupdf needs at least 34000ish (sizeof(fz_shade))/ */
74 #define MEMENTO_PTRSEARCH 65536
75 
76 #ifndef MEMENTO_MAXPATTERN
77 #define MEMENTO_MAXPATTERN 0
78 #endif
79 
80 #ifdef MEMENTO
81 
82 #ifdef MEMENTO_GS_HACKS
83 #include "valgrind.h"
84 #else
85 #ifdef HAVE_VALGRIND
86 #include "valgrind/memcheck.h"
87 #else
88 #define VALGRIND_MAKE_MEM_NOACCESS(p,s)  do { } while (0==1)
89 #define VALGRIND_MAKE_MEM_UNDEFINED(p,s)  do { } while (0==1)
90 #define VALGRIND_MAKE_MEM_DEFINED(p,s)  do { } while (0==1)
91 #endif
92 #endif
93 
94 enum {
95     Memento_PreSize  = 16,
96     Memento_PostSize = 16
97 };
98 
99 enum {
100     Memento_Flag_OldBlock = 1,
101     Memento_Flag_HasParent = 2,
102     Memento_Flag_BreakOnFree = 4,
103     Memento_Flag_BreakOnRealloc = 8
104 };
105 
106 /* When we list leaked blocks at the end of execution, we search for pointers
107  * between blocks in order to be able to give a nice nested view.
108  * Unfortunately, if you have are running your own allocator (such as
109  * ghostscripts chunk allocator) you can often find that the header of the
110  * block always contains pointers to next or previous blocks. This tends to
111  * mean the nesting displayed is "uninteresting" at best :)
112  *
113  * As a hack to get around this, we have a define MEMENTO_SKIP_SEARCH that
114  * indicates how many bytes to skip over at the start of the chunk.
115  * This may cause us to miss true nestings, but such is life...
116  */
117 #ifndef MEMENTO_SEARCH_SKIP
118 #ifdef MEMENTO_GS_HACKS
119 #define MEMENTO_SEARCH_SKIP (2*sizeof(void *))
120 #else
121 #define MEMENTO_SEARCH_SKIP 0
122 #endif
123 #endif
124 
125 typedef struct Memento_BlkHeader Memento_BlkHeader;
126 
127 struct Memento_BlkHeader
128 {
129     size_t             rawsize;
130     int                sequence;
131     int                lastCheckedOK;
132     int                flags;
133     Memento_BlkHeader *next;
134     Memento_BlkHeader *parent; /* Only used while printing out nested list */
135 
136     const char        *label;
137 
138     /* Entries for nesting display calculations */
139     Memento_BlkHeader *child;
140     Memento_BlkHeader *sibling;
141 
142     char               preblk[Memento_PreSize];
143 };
144 
145 /* In future this could (should) be a smarter data structure, like, say,
146  * splay trees. For now, we use a list.
147  */
148 typedef struct Memento_Blocks
149 {
150     Memento_BlkHeader  *head;
151     Memento_BlkHeader **tail;
152 } Memento_Blocks;
153 
154 /* And our global structure */
155 static struct {
156     int            inited;
157     Memento_Blocks used;
158     Memento_Blocks free;
159     size_t         freeListSize;
160     int            sequence;
161     int            paranoia;
162     int            paranoidAt;
163     int            countdown;
164     int            lastChecked;
165     int            breakAt;
166     int            failAt;
167     int            failing;
168     int            nextFailAt;
169     int            squeezeAt;
170     int            squeezing;
171     int            segv;
172     int            pattern;
173     int            nextPattern;
174     int            patternBit;
175     size_t         maxMemory;
176     size_t         alloc;
177     size_t         peakAlloc;
178     size_t         totalAlloc;
179     size_t         numMallocs;
180     size_t         numFrees;
181     size_t         numReallocs;
182 } globals;
183 
184 #define MEMENTO_EXTRASIZE (sizeof(Memento_BlkHeader) + Memento_PostSize)
185 
186 /* Round up size S to the next multiple of N (where N is a power of 2) */
187 #define MEMENTO_ROUNDUP(S,N) ((S + N-1)&~(N-1))
188 
189 #define MEMBLK_SIZE(s) MEMENTO_ROUNDUP(s + MEMENTO_EXTRASIZE, MEMENTO_MAXALIGN)
190 
191 #define MEMBLK_FROMBLK(B)   (&((Memento_BlkHeader*)(void *)(B))[-1])
192 #define MEMBLK_TOBLK(B)     ((void*)(&((Memento_BlkHeader*)(void*)(B))[1]))
193 #define MEMBLK_POSTPTR(B) \
194           (&((char *)(void *)(B))[(B)->rawsize + sizeof(Memento_BlkHeader)])
195 
Memento_breakpoint(void)196 void Memento_breakpoint(void)
197 {
198     /* A handy externally visible function for breakpointing */
199 #if 0 /* Enable this to force automatic breakpointing */
200 #ifdef DEBUG
201 #ifdef _MSC_VER
202     __asm int 3;
203 #endif
204 #endif
205 #endif
206 }
207 
Memento_addBlockHead(Memento_Blocks * blks,Memento_BlkHeader * b,int type)208 static void Memento_addBlockHead(Memento_Blocks    *blks,
209                                  Memento_BlkHeader *b,
210                                  int                type)
211 {
212     if (blks->tail == &blks->head) {
213         /* Adding into an empty list, means the tail changes too */
214         blks->tail = &b->next;
215     }
216     b->next    = blks->head;
217     blks->head = b;
218 #ifndef MEMENTO_LEAKONLY
219     memset(b->preblk, MEMENTO_PREFILL, Memento_PreSize);
220     memset(MEMBLK_POSTPTR(b), MEMENTO_POSTFILL, Memento_PostSize);
221 #endif
222     VALGRIND_MAKE_MEM_NOACCESS(MEMBLK_POSTPTR(b), Memento_PostSize);
223     if (type == 0) { /* malloc */
224         VALGRIND_MAKE_MEM_UNDEFINED(MEMBLK_TOBLK(b), b->rawsize);
225     } else if (type == 1) { /* free */
226         VALGRIND_MAKE_MEM_NOACCESS(MEMBLK_TOBLK(b), b->rawsize);
227     }
228     VALGRIND_MAKE_MEM_NOACCESS(b, sizeof(Memento_BlkHeader));
229 }
230 
Memento_addBlockTail(Memento_Blocks * blks,Memento_BlkHeader * b,int type)231 static void Memento_addBlockTail(Memento_Blocks    *blks,
232                                  Memento_BlkHeader *b,
233                                  int                type)
234 {
235     VALGRIND_MAKE_MEM_DEFINED(blks->tail, sizeof(Memento_BlkHeader *));
236     *blks->tail = b;
237     blks->tail  = &b->next;
238     b->next = NULL;
239     VALGRIND_MAKE_MEM_NOACCESS(blks->tail, sizeof(Memento_BlkHeader *));
240 #ifndef MEMENTO_LEAKONLY
241     memset(b->preblk, MEMENTO_PREFILL, Memento_PreSize);
242     memset(MEMBLK_POSTPTR(b), MEMENTO_POSTFILL, Memento_PostSize);
243 #endif
244     VALGRIND_MAKE_MEM_NOACCESS(MEMBLK_POSTPTR(b), Memento_PostSize);
245     if (type == 0) { /* malloc */
246         VALGRIND_MAKE_MEM_UNDEFINED(MEMBLK_TOBLK(b), b->rawsize);
247     } else if (type == 1) { /* free */
248         VALGRIND_MAKE_MEM_NOACCESS(MEMBLK_TOBLK(b), b->rawsize);
249     }
250     VALGRIND_MAKE_MEM_NOACCESS(b, sizeof(Memento_BlkHeader));
251 }
252 
253 typedef struct BlkCheckData {
254     int found;
255     int preCorrupt;
256     int postCorrupt;
257     int freeCorrupt;
258     int index;
259 } BlkCheckData;
260 
Memento_Internal_checkAllocedBlock(Memento_BlkHeader * b,void * arg)261 static int Memento_Internal_checkAllocedBlock(Memento_BlkHeader *b, void *arg)
262 {
263 #ifndef MEMENTO_LEAKONLY
264     int           i;
265     char         *p;
266     int           corrupt = 0;
267     BlkCheckData *data = (BlkCheckData *)arg;
268 
269     p = b->preblk;
270     i = Memento_PreSize;
271     do {
272         corrupt |= (*p++ ^ (char)MEMENTO_PREFILL);
273     } while (--i);
274     if (corrupt) {
275         data->preCorrupt = 1;
276     }
277     p = MEMBLK_POSTPTR(b);
278     i = Memento_PreSize;
279     do {
280         corrupt |= (*p++ ^ (char)MEMENTO_POSTFILL);
281     } while (--i);
282     if (corrupt) {
283         data->postCorrupt = 1;
284     }
285     if ((data->freeCorrupt | data->preCorrupt | data->postCorrupt) == 0) {
286         b->lastCheckedOK = globals.sequence;
287     }
288     data->found |= 1;
289 #endif
290     return 0;
291 }
292 
Memento_Internal_checkFreedBlock(Memento_BlkHeader * b,void * arg)293 static int Memento_Internal_checkFreedBlock(Memento_BlkHeader *b, void *arg)
294 {
295 #ifndef MEMENTO_LEAKONLY
296     int           i;
297     char         *p;
298     BlkCheckData *data = (BlkCheckData *)arg;
299 
300     p = MEMBLK_TOBLK(b);
301     i = b->rawsize;
302     /* Attempt to speed this up by checking an (aligned) int at a time */
303     do {
304         if (((size_t)p) & 1) {
305             if (*p++ != (char)MEMENTO_FREEFILL)
306                 break;
307             i--;
308             if (i == 0)
309                 break;
310         }
311         if ((i >= 2) && (((size_t)p) & 2)) {
312             if (*(short *)p != (short)(MEMENTO_FREEFILL | (MEMENTO_FREEFILL<<8)))
313                 goto mismatch;
314             p += 2;
315             i -= 2;
316             if (i == 0)
317                 break;
318         }
319         i -= 4;
320         while (i >= 0) {
321             if (*(int *)p != (MEMENTO_FREEFILL |
322                               (MEMENTO_FREEFILL<<8) |
323                               (MEMENTO_FREEFILL<<16) |
324                               (MEMENTO_FREEFILL<<24)))
325                 goto mismatch;
326             p += 4;
327             i -= 4;
328         }
329         i += 4;
330         if ((i >= 2) && (((size_t)p) & 2)) {
331             if (*(short *)p != (short)(MEMENTO_FREEFILL | (MEMENTO_FREEFILL<<8)))
332                 goto mismatch;
333             p += 2;
334             i -= 2;
335         }
336 mismatch:
337         while (i) {
338             if (*p++ != (char)MEMENTO_FREEFILL)
339                 break;
340             i--;
341         }
342     } while (0);
343     if (i) {
344         data->freeCorrupt = 1;
345         data->index       = b->rawsize-i;
346     }
347     return Memento_Internal_checkAllocedBlock(b, arg);
348 #else
349     return 0;
350 #endif
351 }
352 
Memento_removeBlock(Memento_Blocks * blks,Memento_BlkHeader * b)353 static void Memento_removeBlock(Memento_Blocks    *blks,
354                                 Memento_BlkHeader *b)
355 {
356     Memento_BlkHeader *head = blks->head;
357     Memento_BlkHeader *prev = NULL;
358     while ((head) && (head != b)) {
359         VALGRIND_MAKE_MEM_DEFINED(head, sizeof(*head));
360         prev = head;
361         head = head->next;
362         VALGRIND_MAKE_MEM_NOACCESS(prev, sizeof(*prev));
363     }
364     if (head == NULL) {
365         /* FAIL! Will have been reported to user earlier, so just exit. */
366         return;
367     }
368     VALGRIND_MAKE_MEM_DEFINED(blks->tail, sizeof(*blks->tail));
369     if (*blks->tail == head) {
370         /* Removing the tail of the list */
371         if (prev == NULL) {
372             /* Which is also the head */
373             blks->tail = &blks->head;
374         } else {
375             /* Which isn't the head */
376             blks->tail = &prev->next;
377         }
378     }
379     if (prev == NULL) {
380         /* Removing from the head of the list */
381         VALGRIND_MAKE_MEM_DEFINED(head, sizeof(*head));
382         blks->head = head->next;
383         VALGRIND_MAKE_MEM_NOACCESS(head, sizeof(*head));
384     } else {
385         /* Removing from not-the-head */
386         VALGRIND_MAKE_MEM_DEFINED(head, sizeof(*head));
387         VALGRIND_MAKE_MEM_DEFINED(prev, sizeof(*prev));
388         prev->next = head->next;
389         VALGRIND_MAKE_MEM_NOACCESS(head, sizeof(*head));
390         VALGRIND_MAKE_MEM_NOACCESS(prev, sizeof(*prev));
391     }
392 }
393 
Memento_Internal_makeSpace(size_t space)394 static int Memento_Internal_makeSpace(size_t space)
395 {
396     /* If too big, it can never go on the freelist */
397     if (space > MEMENTO_FREELIST_MAX_SINGLE_BLOCK)
398         return 0;
399     /* Pretend we added it on. */
400     globals.freeListSize += space;
401     /* Ditch blocks until it fits within our limit */
402     while (globals.freeListSize > MEMENTO_FREELIST_MAX) {
403         Memento_BlkHeader *head = globals.free.head;
404         VALGRIND_MAKE_MEM_DEFINED(head, sizeof(*head));
405         globals.free.head = head->next;
406         globals.freeListSize -= MEMBLK_SIZE(head->rawsize);
407         MEMENTO_UNDERLYING_FREE(head);
408     }
409     /* Make sure we haven't just completely emptied the free list */
410     /* (This should never happen, but belt and braces... */
411     if (globals.free.head == NULL)
412         globals.free.tail = &globals.free.head;
413     return 1;
414 }
415 
Memento_appBlocks(Memento_Blocks * blks,int (* app)(Memento_BlkHeader *,void *),void * arg)416 static int Memento_appBlocks(Memento_Blocks *blks,
417                              int             (*app)(Memento_BlkHeader *,
418                                                     void *),
419                              void           *arg)
420 {
421     Memento_BlkHeader *head = blks->head;
422     Memento_BlkHeader *next;
423     int                result;
424     while (head) {
425         VALGRIND_MAKE_MEM_DEFINED(head, sizeof(Memento_BlkHeader));
426         VALGRIND_MAKE_MEM_DEFINED(MEMBLK_TOBLK(head),
427                                   head->rawsize + Memento_PostSize);
428         result = app(head, arg);
429         next = head->next;
430         VALGRIND_MAKE_MEM_NOACCESS(MEMBLK_POSTPTR(head), Memento_PostSize);
431         VALGRIND_MAKE_MEM_NOACCESS(head, sizeof(Memento_BlkHeader));
432         if (result)
433             return result;
434         head = next;
435     }
436     return 0;
437 }
438 
Memento_appBlock(Memento_Blocks * blks,int (* app)(Memento_BlkHeader *,void *),void * arg,Memento_BlkHeader * b)439 static int Memento_appBlock(Memento_Blocks    *blks,
440                             int                (*app)(Memento_BlkHeader *,
441                                                       void *),
442                             void              *arg,
443                             Memento_BlkHeader *b)
444 {
445     Memento_BlkHeader *head = blks->head;
446     Memento_BlkHeader *next;
447     int                result;
448     while (head && head != b) {
449         VALGRIND_MAKE_MEM_DEFINED(head, sizeof(Memento_BlkHeader));
450         next = head->next;
451         VALGRIND_MAKE_MEM_NOACCESS(MEMBLK_POSTPTR(head), Memento_PostSize);
452         head = next;
453     }
454     if (head == b) {
455         VALGRIND_MAKE_MEM_DEFINED(head, sizeof(Memento_BlkHeader));
456         VALGRIND_MAKE_MEM_DEFINED(MEMBLK_TOBLK(head),
457                                   head->rawsize + Memento_PostSize);
458         result = app(head, arg);
459         VALGRIND_MAKE_MEM_NOACCESS(MEMBLK_POSTPTR(head), Memento_PostSize);
460         VALGRIND_MAKE_MEM_NOACCESS(head, sizeof(Memento_BlkHeader));
461         return result;
462     }
463     return 0;
464 }
465 
showBlock(Memento_BlkHeader * b,int space)466 static void showBlock(Memento_BlkHeader *b, int space)
467 {
468     fprintf(stderr, "0x%p:(size=%d,num=%d)",
469             MEMBLK_TOBLK(b), (int)b->rawsize, b->sequence);
470     if (b->label)
471         fprintf(stderr, "%c(%s)", space, b->label);
472 }
473 
blockDisplay(Memento_BlkHeader * b,int n)474 static void blockDisplay(Memento_BlkHeader *b, int n)
475 {
476     n++;
477     while(n > 0)
478     {
479         int i = n;
480         if (i > 32)
481             i = 32;
482         n -= i;
483         fprintf(stderr, "%s", &"                                "[32-i]);
484     }
485     showBlock(b, '\t');
486     fprintf(stderr, "\n");
487 }
488 
Memento_listBlock(Memento_BlkHeader * b,void * arg)489 static int Memento_listBlock(Memento_BlkHeader *b,
490                              void              *arg)
491 {
492     int *counts = (int *)arg;
493     blockDisplay(b, 0);
494     counts[0]++;
495     counts[1]+= b->rawsize;
496     return 0;
497 }
498 
doNestedDisplay(Memento_BlkHeader * b,int depth)499 static void doNestedDisplay(Memento_BlkHeader *b,
500                             int depth)
501 {
502     blockDisplay(b, depth);
503     for (b = b->child; b; b = b->sibling)
504         doNestedDisplay(b, depth+1);
505 }
506 
ptrcmp(const void * a_,const void * b_)507 static int ptrcmp(const void *a_, const void *b_)
508 {
509     const char **a = (const char **)a_;
510     const char **b = (const char **)b_;
511     return (int)(*a-*b);
512 }
513 
514 static
Memento_listBlocksNested(void)515 int Memento_listBlocksNested(void)
516 {
517     int count, size, i;
518     Memento_BlkHeader *b;
519     void **blocks, *minptr, *maxptr;
520     long mask;
521 
522     /* Count the blocks */
523     count = 0;
524     size = 0;
525     for (b = globals.used.head; b; b = b->next) {
526         size += b->rawsize;
527         count++;
528     }
529 
530     /* Make our block list */
531     blocks = MEMENTO_UNDERLYING_MALLOC(sizeof(void *) * count);
532     if (blocks == NULL)
533         return 1;
534 
535     /* Populate our block list */
536     b = globals.used.head;
537     minptr = maxptr = MEMBLK_TOBLK(b);
538     mask = (long)minptr;
539     for (i = 0; b; b = b->next, i++) {
540         void *p = MEMBLK_TOBLK(b);
541         mask &= (long)p;
542         if (p < minptr)
543             minptr = p;
544         if (p > maxptr)
545             maxptr = p;
546         blocks[i] = p;
547         b->flags &= ~Memento_Flag_HasParent;
548         b->child   = NULL;
549         b->sibling = NULL;
550         b->parent  = NULL;
551     }
552     qsort(blocks, count, sizeof(void *), ptrcmp);
553 
554     /* Now, calculate tree */
555     for (b = globals.used.head; b; b = b->next) {
556         char *p = MEMBLK_TOBLK(b);
557         int end = (b->rawsize < MEMENTO_PTRSEARCH ? b->rawsize : MEMENTO_PTRSEARCH);
558         for (i = MEMENTO_SEARCH_SKIP; i < end; i += sizeof(void *)) {
559             void *q = *(void **)(&p[i]);
560             void **r;
561 
562             /* Do trivial checks on pointer */
563             if ((mask & (int)q) != mask || q < minptr || q > maxptr)
564                 continue;
565 
566             /* Search for pointer */
567             r = bsearch(&q, blocks, count, sizeof(void *), ptrcmp);
568             if (r) {
569                 /* Found child */
570                 Memento_BlkHeader *child = MEMBLK_FROMBLK(*r);
571                 Memento_BlkHeader *parent;
572 
573                 /* We're assuming tree structure, not graph - ignore second
574                  * and subsequent pointers. */
575                 if (child->parent != NULL)
576                     continue;
577                 if (child->flags & Memento_Flag_HasParent)
578                     continue;
579 
580                 /* We're also assuming acyclicness here. If this is one of
581                  * our parents, ignore it. */
582                 parent = b->parent;
583                 while (parent != NULL && parent != child)
584                     parent = parent->parent;
585                 if (parent == child)
586                     continue;
587 
588                 child->sibling = b->child;
589                 b->child = child;
590                 child->parent = b;
591                 child->flags |= Memento_Flag_HasParent;
592             }
593         }
594     }
595 
596     /* Now display with nesting */
597     for (b = globals.used.head; b; b = b->next) {
598         if ((b->flags & Memento_Flag_HasParent) == 0)
599             doNestedDisplay(b, 0);
600     }
601     fprintf(stderr, " Total number of blocks = %d\n", count);
602     fprintf(stderr, " Total size of blocks = %d\n", size);
603 
604     MEMENTO_UNDERLYING_FREE(blocks);
605     return 0;
606 }
607 
Memento_listBlocks(void)608 void Memento_listBlocks(void)
609 {
610     fprintf(stderr, "Allocated blocks:\n");
611     if (Memento_listBlocksNested())
612     {
613         int counts[2];
614         counts[0] = 0;
615         counts[1] = 0;
616         Memento_appBlocks(&globals.used, Memento_listBlock, &counts[0]);
617         fprintf(stderr, " Total number of blocks = %d\n", counts[0]);
618         fprintf(stderr, " Total size of blocks = %d\n", counts[1]);
619     }
620 }
621 
Memento_listNewBlock(Memento_BlkHeader * b,void * arg)622 static int Memento_listNewBlock(Memento_BlkHeader *b,
623                                 void              *arg)
624 {
625     if (b->flags & Memento_Flag_OldBlock)
626         return 0;
627     b->flags |= Memento_Flag_OldBlock;
628     return Memento_listBlock(b, arg);
629 }
630 
Memento_listNewBlocks(void)631 void Memento_listNewBlocks(void) {
632     int counts[2];
633     counts[0] = 0;
634     counts[1] = 0;
635     fprintf(stderr, "Blocks allocated and still extant since last list:\n");
636     Memento_appBlocks(&globals.used, Memento_listNewBlock, &counts[0]);
637     fprintf(stderr, "  Total number of blocks = %d\n", counts[0]);
638     fprintf(stderr, "  Total size of blocks = %d\n", counts[1]);
639 }
640 
Memento_endStats(void)641 static void Memento_endStats(void)
642 {
643     fprintf(stderr, "Total memory malloced = %u bytes\n", (unsigned int)globals.totalAlloc);
644     fprintf(stderr, "Peak memory malloced = %u bytes\n", (unsigned int)globals.peakAlloc);
645     fprintf(stderr, "%u mallocs, %u frees, %u reallocs\n", (unsigned int)globals.numMallocs,
646             (unsigned int)globals.numFrees, (unsigned int)globals.numReallocs);
647     fprintf(stderr, "Average allocation size %u bytes\n", (unsigned int)
648             (globals.numMallocs != 0 ? globals.totalAlloc/globals.numMallocs: 0));
649 }
650 
Memento_stats(void)651 void Memento_stats(void)
652 {
653     fprintf(stderr, "Current memory malloced = %u bytes\n", (unsigned int)globals.alloc);
654     Memento_endStats();
655 }
656 
Memento_fin(void)657 static void Memento_fin(void)
658 {
659     Memento_checkAllMemory();
660     Memento_endStats();
661     if (globals.used.head != NULL) {
662         Memento_listBlocks();
663         Memento_breakpoint();
664     }
665     if (globals.segv) {
666         fprintf(stderr, "Memory dumped on SEGV while squeezing @ %d\n", globals.failAt);
667     } else if (globals.squeezing) {
668         if (globals.pattern == 0)
669             fprintf(stderr, "Memory squeezing @ %d complete\n", globals.squeezeAt);
670         else
671             fprintf(stderr, "Memory squeezing @ %d (%d) complete\n", globals.squeezeAt, globals.pattern);
672     }
673     if (globals.failing)
674     {
675         fprintf(stderr, "MEMENTO_FAILAT=%d\n", globals.failAt);
676         fprintf(stderr, "MEMENTO_PATTERN=%d\n", globals.pattern);
677     }
678     if (globals.nextFailAt != 0)
679     {
680         fprintf(stderr, "MEMENTO_NEXTFAILAT=%d\n", globals.nextFailAt);
681         fprintf(stderr, "MEMENTO_NEXTPATTERN=%d\n", globals.nextPattern);
682     }
683 }
684 
Memento_inited(void)685 static void Memento_inited(void)
686 {
687     /* A good place for a breakpoint */
688 }
689 
Memento_init(void)690 static void Memento_init(void)
691 {
692     char *env;
693     memset(&globals, 0, sizeof(globals));
694     globals.inited    = 1;
695     globals.used.head = NULL;
696     globals.used.tail = &globals.used.head;
697     globals.free.head = NULL;
698     globals.free.tail = &globals.free.head;
699     globals.sequence  = 0;
700     globals.countdown = 1024;
701 
702     env = getenv("MEMENTO_FAILAT");
703     globals.failAt = (env ? atoi(env) : 0);
704 
705     env = getenv("MEMENTO_PARANOIA");
706     globals.paranoia = (env ? atoi(env) : 0);
707     if (globals.paranoia == 0)
708         globals.paranoia = 1024;
709 
710     env = getenv("MEMENTO_PARANOIDAT");
711     globals.paranoidAt = (env ? atoi(env) : 0);
712 
713     env = getenv("MEMENTO_SQUEEZEAT");
714     globals.squeezeAt = (env ? atoi(env) : 0);
715 
716     env = getenv("MEMENTO_PATTERN");
717     globals.pattern = (env ? atoi(env) : 0);
718 
719     env = getenv("MEMENTO_MAXMEMORY");
720     globals.maxMemory = (env ? atoi(env) : 0);
721 
722     atexit(Memento_fin);
723 
724     Memento_inited();
725 }
726 
727 #ifdef MEMENTO_HAS_FORK
728 #include <unistd.h>
729 #include <sys/wait.h>
730 #ifdef MEMENTO_STACKTRACE_METHOD
731 #if MEMENTO_STACKTRACE_METHOD == 1
732 #include <signal.h>
733 #endif
734 #endif
735 
736 /* FIXME: Find some portable way of getting this */
737 /* MacOSX has 10240, Ubuntu seems to have 256 */
738 #define OPEN_MAX 10240
739 
740 /* stashed_map[j] = i means that filedescriptor i-1 was duplicated to j */
741 int stashed_map[OPEN_MAX];
742 
743 extern size_t backtrace(void **, int);
744 extern void backtrace_symbols_fd(void **, size_t, int);
745 
Memento_signal(void)746 static void Memento_signal(void)
747 {
748     fprintf(stderr, "SEGV after Memory squeezing @ %d\n", globals.squeezeAt);
749 
750 #ifdef MEMENTO_STACKTRACE_METHOD
751 #if MEMENTO_STACKTRACE_METHOD == 1
752     {
753       void *array[100];
754       size_t size;
755 
756       size = backtrace(array, 100);
757       fprintf(stderr, "------------------------------------------------------------------------\n");
758       fprintf(stderr, "Backtrace:\n");
759       backtrace_symbols_fd(array, size, 2);
760       fprintf(stderr, "------------------------------------------------------------------------\n");
761     }
762 #endif
763 #endif
764 
765     exit(1);
766 }
767 
squeeze(void)768 static int squeeze(void)
769 {
770     pid_t pid;
771     int i, status;
772 
773     if (globals.patternBit < 0)
774         return 1;
775     if (globals.squeezing && globals.patternBit >= MEMENTO_MAXPATTERN)
776         return 1;
777 
778     if (globals.patternBit == 0)
779         globals.squeezeAt = globals.sequence;
780 
781     if (!globals.squeezing) {
782         fprintf(stderr, "Memory squeezing @ %d\n", globals.squeezeAt);
783     } else
784         fprintf(stderr, "Memory squeezing @ %d (%x,%x)\n", globals.squeezeAt, globals.pattern, globals.patternBit);
785 
786     /* When we fork below, the child is going to snaffle all our file pointers
787      * and potentially corrupt them. Let's make copies of all of them before
788      * we fork, so we can restore them when we restart. */
789     for (i = 0; i < OPEN_MAX; i++) {
790         if (stashed_map[i] == 0) {
791             int j = dup(i);
792             stashed_map[j] = i+1;
793         }
794     }
795 
796     pid = fork();
797     if (pid == 0) {
798         /* Child */
799         signal(SIGSEGV, Memento_signal);
800         /* In the child, we always fail the next allocation. */
801         if (globals.patternBit == 0) {
802             globals.patternBit = 1;
803         } else
804             globals.patternBit <<= 1;
805         globals.squeezing = 1;
806         return 1;
807     }
808 
809     /* In the parent if we hit another allocation, pass it (and record the
810      * fact we passed it in the pattern. */
811     globals.pattern |= globals.patternBit;
812     globals.patternBit <<= 1;
813 
814     /* Wait for pid to finish */
815     waitpid(pid, &status, 0);
816 
817     if (status != 0) {
818         fprintf(stderr, "Child status=%d\n", status);
819     }
820 
821     /* Put the files back */
822     for (i = 0; i < OPEN_MAX; i++) {
823         if (stashed_map[i] != 0) {
824             dup2(i, stashed_map[i]-1);
825             close(i);
826             stashed_map[i] = 0;
827         }
828     }
829 
830     return 0;
831 }
832 #else
833 #include <signal.h>
834 
Memento_signal(void)835 static void Memento_signal(void)
836 {
837     globals.segv = 1;
838     /* If we just return from this function the SEGV will be unhandled, and
839      * we'll launch into whatever JIT debugging system the OS provides. At
840      * least output something useful first. If MEMENTO_NOJIT is set, then
841      * just exit to avoid the JIT (and get the usual atexit handling). */
842     if (getenv("MEMENTO_NOJIT"))
843         exit(1);
844     else
845         Memento_fin();
846 }
847 
squeeze(void)848 int squeeze(void)
849 {
850     fprintf(stderr, "Memento memory squeezing disabled as no fork!\n");
851     return 0;
852 }
853 #endif
854 
Memento_startFailing(void)855 static void Memento_startFailing(void)
856 {
857     if (!globals.failing) {
858         fprintf(stderr, "Starting to fail...\n");
859         fflush(stderr);
860         globals.failing = 1;
861         globals.failAt = globals.sequence;
862         globals.nextFailAt = globals.sequence+1;
863         globals.pattern = 0;
864         globals.patternBit = 0;
865         signal(SIGSEGV, Memento_signal);
866         signal(SIGABRT, Memento_signal);
867         Memento_breakpoint();
868     }
869 }
870 
Memento_event(void)871 static void Memento_event(void)
872 {
873     globals.sequence++;
874     if ((globals.sequence >= globals.paranoidAt) && (globals.paranoidAt != 0)) {
875         globals.paranoia = 1;
876         globals.countdown = 1;
877     }
878     if (--globals.countdown == 0) {
879         Memento_checkAllMemory();
880         globals.countdown = globals.paranoia;
881     }
882 
883     if (globals.sequence == globals.breakAt) {
884         fprintf(stderr, "Breaking at event %d\n", globals.breakAt);
885         Memento_breakpoint();
886     }
887 }
888 
Memento_breakAt(int event)889 int Memento_breakAt(int event)
890 {
891     globals.breakAt = event;
892     return event;
893 }
894 
Memento_label(void * ptr,const char * label)895 void *Memento_label(void *ptr, const char *label)
896 {
897     Memento_BlkHeader *block;
898 
899     if (ptr == NULL)
900         return NULL;
901     block = MEMBLK_FROMBLK(ptr);
902     block->label = label;
903     return ptr;
904 }
905 
Memento_failThisEvent(void)906 int Memento_failThisEvent(void)
907 {
908     int failThisOne;
909 
910     if (!globals.inited)
911         Memento_init();
912 
913     Memento_event();
914 
915     if ((globals.sequence >= globals.failAt) && (globals.failAt != 0))
916         Memento_startFailing();
917     if ((globals.sequence >= globals.squeezeAt) && (globals.squeezeAt != 0)) {
918         return squeeze();
919     }
920 
921     if (!globals.failing)
922         return 0;
923     failThisOne = ((globals.patternBit & globals.pattern) == 0);
924     /* If we are failing, and we've reached the end of the pattern and we've
925      * still got bits available in the pattern word, and we haven't already
926      * set a nextPattern, then extend the pattern. */
927     if (globals.failing &&
928         ((~(globals.patternBit-1) & globals.pattern) == 0) &&
929         (globals.patternBit != 0) &&
930         globals.nextPattern == 0)
931     {
932         /* We'll fail this one, and set the 'next' one to pass it. */
933         globals.nextFailAt = globals.failAt;
934         globals.nextPattern = globals.pattern | globals.patternBit;
935     }
936     globals.patternBit = (globals.patternBit ? globals.patternBit << 1 : 1);
937 
938     return failThisOne;
939 }
940 
Memento_malloc(size_t s)941 void *Memento_malloc(size_t s)
942 {
943     Memento_BlkHeader *memblk;
944     size_t             smem = MEMBLK_SIZE(s);
945 
946     if (Memento_failThisEvent())
947         return NULL;
948 
949     if (s == 0)
950         return NULL;
951 
952     globals.numMallocs++;
953 
954     if (globals.maxMemory != 0 && globals.alloc + s > globals.maxMemory)
955         return NULL;
956 
957     memblk = MEMENTO_UNDERLYING_MALLOC(smem);
958     if (memblk == NULL)
959         return NULL;
960 
961     globals.alloc      += s;
962     globals.totalAlloc += s;
963     if (globals.peakAlloc < globals.alloc)
964         globals.peakAlloc = globals.alloc;
965 #ifndef MEMENTO_LEAKONLY
966     memset(MEMBLK_TOBLK(memblk), MEMENTO_ALLOCFILL, s);
967 #endif
968     memblk->rawsize       = s;
969     memblk->sequence      = globals.sequence;
970     memblk->lastCheckedOK = memblk->sequence;
971     memblk->flags         = 0;
972     memblk->label         = 0;
973     memblk->child         = NULL;
974     memblk->sibling       = NULL;
975     Memento_addBlockHead(&globals.used, memblk, 0);
976     return MEMBLK_TOBLK(memblk);
977 }
978 
Memento_calloc(size_t n,size_t s)979 void *Memento_calloc(size_t n, size_t s)
980 {
981     void *block = Memento_malloc(n*s);
982 
983     if (block)
984         memset(block, 0, n*s);
985     return block;
986 }
987 
checkBlock(Memento_BlkHeader * memblk,const char * action)988 static int checkBlock(Memento_BlkHeader *memblk, const char *action)
989 {
990 #ifndef MEMENTO_LEAKONLY
991     BlkCheckData data;
992 
993     memset(&data, 0, sizeof(data));
994     Memento_appBlock(&globals.used, Memento_Internal_checkAllocedBlock,
995                      &data, memblk);
996     if (!data.found) {
997         /* Failure! */
998         fprintf(stderr, "Attempt to %s block ", action);
999         showBlock(memblk, 32);
1000         Memento_breakpoint();
1001         return 1;
1002     } else if (data.preCorrupt || data.postCorrupt) {
1003         fprintf(stderr, "Block ");
1004         showBlock(memblk, ' ');
1005         fprintf(stderr, " found to be corrupted on %s!\n", action);
1006         if (data.preCorrupt) {
1007             fprintf(stderr, "Preguard corrupted\n");
1008         }
1009         if (data.postCorrupt) {
1010             fprintf(stderr, "Postguard corrupted\n");
1011         }
1012         fprintf(stderr, "Block last checked OK at allocation %d. Now %d.\n",
1013                 memblk->lastCheckedOK, globals.sequence);
1014         Memento_breakpoint();
1015         return 1;
1016     }
1017 #endif
1018     return 0;
1019 }
1020 
Memento_free(void * blk)1021 void Memento_free(void *blk)
1022 {
1023     Memento_BlkHeader *memblk;
1024 
1025     if (!globals.inited)
1026         Memento_init();
1027 
1028     Memento_event();
1029 
1030     if (blk == NULL)
1031         return;
1032 
1033     memblk = MEMBLK_FROMBLK(blk);
1034     VALGRIND_MAKE_MEM_DEFINED(memblk, sizeof(*memblk));
1035     if (checkBlock(memblk, "free"))
1036         return;
1037 
1038     if (memblk->flags & Memento_Flag_BreakOnFree)
1039         Memento_breakpoint();
1040 
1041     VALGRIND_MAKE_MEM_DEFINED(memblk, sizeof(*memblk));
1042     globals.alloc -= memblk->rawsize;
1043     globals.numFrees++;
1044 
1045     Memento_removeBlock(&globals.used, memblk);
1046 
1047     VALGRIND_MAKE_MEM_DEFINED(memblk, sizeof(*memblk));
1048     if (Memento_Internal_makeSpace(MEMBLK_SIZE(memblk->rawsize))) {
1049         VALGRIND_MAKE_MEM_DEFINED(memblk, sizeof(*memblk));
1050         VALGRIND_MAKE_MEM_DEFINED(MEMBLK_TOBLK(memblk),
1051                                   memblk->rawsize + Memento_PostSize);
1052 #ifndef MEMENTO_LEAKONLY
1053         memset(MEMBLK_TOBLK(memblk), MEMENTO_FREEFILL, memblk->rawsize);
1054 #endif
1055         Memento_addBlockTail(&globals.free, memblk, 1);
1056     } else {
1057         MEMENTO_UNDERLYING_FREE(memblk);
1058     }
1059 }
1060 
Memento_realloc(void * blk,size_t newsize)1061 void *Memento_realloc(void *blk, size_t newsize)
1062 {
1063     Memento_BlkHeader *memblk, *newmemblk;
1064     size_t             newsizemem;
1065     int                flags;
1066 
1067     if (blk == NULL)
1068         return Memento_malloc(newsize);
1069     if (newsize == 0) {
1070         Memento_free(blk);
1071         return NULL;
1072     }
1073 
1074     if (Memento_failThisEvent())
1075         return NULL;
1076 
1077     memblk     = MEMBLK_FROMBLK(blk);
1078     if (checkBlock(memblk, "realloc"))
1079         return NULL;
1080 
1081     if (memblk->flags & Memento_Flag_BreakOnRealloc)
1082         Memento_breakpoint();
1083 
1084     if (globals.maxMemory != 0 && globals.alloc - memblk->rawsize + newsize > globals.maxMemory)
1085         return NULL;
1086 
1087     newsizemem = MEMBLK_SIZE(newsize);
1088     Memento_removeBlock(&globals.used, memblk);
1089     flags = memblk->flags;
1090     newmemblk  = MEMENTO_UNDERLYING_REALLOC(memblk, newsizemem);
1091     if (newmemblk == NULL)
1092     {
1093         Memento_addBlockHead(&globals.used, memblk, 2);
1094         return NULL;
1095     }
1096     globals.numReallocs++;
1097     globals.totalAlloc += newsize;
1098     globals.alloc      -= newmemblk->rawsize;
1099     globals.alloc      += newsize;
1100     if (globals.peakAlloc < globals.alloc)
1101         globals.peakAlloc = globals.alloc;
1102     newmemblk->flags = flags;
1103     if (newmemblk->rawsize < newsize) {
1104         char *newbytes = ((char *)MEMBLK_TOBLK(newmemblk))+newmemblk->rawsize;
1105 #ifndef MEMENTO_LEAKONLY
1106         memset(newbytes, MEMENTO_ALLOCFILL, newsize - newmemblk->rawsize);
1107 #endif
1108         VALGRIND_MAKE_MEM_UNDEFINED(newbytes, newsize - newmemblk->rawsize);
1109     }
1110     newmemblk->rawsize = newsize;
1111 #ifndef MEMENTO_LEAKONLY
1112     memset(newmemblk->preblk, MEMENTO_PREFILL, Memento_PreSize);
1113     memset(MEMBLK_POSTPTR(newmemblk), MEMENTO_POSTFILL, Memento_PostSize);
1114 #endif
1115     Memento_addBlockHead(&globals.used, newmemblk, 2);
1116     return MEMBLK_TOBLK(newmemblk);
1117 }
1118 
Memento_checkBlock(void * blk)1119 int Memento_checkBlock(void *blk)
1120 {
1121     Memento_BlkHeader *memblk;
1122 
1123     if (blk == NULL)
1124         return 0;
1125     memblk = MEMBLK_FROMBLK(blk);
1126     return checkBlock(memblk, "check");
1127 }
1128 
Memento_Internal_checkAllAlloced(Memento_BlkHeader * memblk,void * arg)1129 static int Memento_Internal_checkAllAlloced(Memento_BlkHeader *memblk, void *arg)
1130 {
1131     BlkCheckData *data = (BlkCheckData *)arg;
1132 
1133     Memento_Internal_checkAllocedBlock(memblk, data);
1134     if (data->preCorrupt || data->postCorrupt) {
1135         if ((data->found & 2) == 0) {
1136             fprintf(stderr, "Allocated blocks:\n");
1137             data->found |= 2;
1138         }
1139         fprintf(stderr, "  Block ");
1140         showBlock(memblk, ' ');
1141         if (data->preCorrupt) {
1142             fprintf(stderr, " Preguard ");
1143         }
1144         if (data->postCorrupt) {
1145             fprintf(stderr, "%s Postguard ",
1146                     (data->preCorrupt ? "&" : ""));
1147         }
1148         fprintf(stderr, "corrupted.\n    "
1149                 "Block last checked OK at allocation %d. Now %d.\n",
1150                 memblk->lastCheckedOK, globals.sequence);
1151         data->preCorrupt  = 0;
1152         data->postCorrupt = 0;
1153         data->freeCorrupt = 0;
1154     }
1155     else
1156         memblk->lastCheckedOK = globals.sequence;
1157     return 0;
1158 }
1159 
Memento_Internal_checkAllFreed(Memento_BlkHeader * memblk,void * arg)1160 static int Memento_Internal_checkAllFreed(Memento_BlkHeader *memblk, void *arg)
1161 {
1162     BlkCheckData *data = (BlkCheckData *)arg;
1163 
1164     Memento_Internal_checkFreedBlock(memblk, data);
1165     if (data->preCorrupt || data->postCorrupt || data->freeCorrupt) {
1166         if ((data->found & 4) == 0) {
1167             fprintf(stderr, "Freed blocks:\n");
1168             data->found |= 4;
1169         }
1170         fprintf(stderr, "  ");
1171         showBlock(memblk, ' ');
1172         if (data->freeCorrupt) {
1173             fprintf(stderr, " index %d (address 0x%p) onwards", data->index,
1174                     &((char *)MEMBLK_TOBLK(memblk))[data->index]);
1175             if (data->preCorrupt) {
1176                 fprintf(stderr, "+ preguard");
1177             }
1178             if (data->postCorrupt) {
1179                 fprintf(stderr, "+ postguard");
1180             }
1181         } else {
1182             if (data->preCorrupt) {
1183                 fprintf(stderr, " preguard");
1184             }
1185             if (data->postCorrupt) {
1186                 fprintf(stderr, "%s Postguard",
1187                         (data->preCorrupt ? "+" : ""));
1188             }
1189         }
1190         fprintf(stderr, " corrupted.\n"
1191                 "    Block last checked OK at allocation %d. Now %d.\n",
1192                 memblk->lastCheckedOK, globals.sequence);
1193         data->preCorrupt  = 0;
1194         data->postCorrupt = 0;
1195         data->freeCorrupt = 0;
1196     }
1197     else
1198         memblk->lastCheckedOK = globals.sequence;
1199     return 0;
1200 }
1201 
Memento_checkAllMemory(void)1202 int Memento_checkAllMemory(void)
1203 {
1204 #ifndef MEMENTO_LEAKONLY
1205     BlkCheckData data;
1206 
1207     memset(&data, 0, sizeof(data));
1208     Memento_appBlocks(&globals.used, Memento_Internal_checkAllAlloced, &data);
1209     Memento_appBlocks(&globals.free, Memento_Internal_checkAllFreed, &data);
1210     if (data.found & 6) {
1211         Memento_breakpoint();
1212         return 1;
1213     }
1214 #endif
1215     return 0;
1216 }
1217 
Memento_setParanoia(int i)1218 int Memento_setParanoia(int i)
1219 {
1220     globals.paranoia = i;
1221     globals.countdown = globals.paranoia;
1222     return i;
1223 }
1224 
Memento_paranoidAt(int i)1225 int Memento_paranoidAt(int i)
1226 {
1227     globals.paranoidAt = i;
1228     return i;
1229 }
1230 
Memento_getBlockNum(void * b)1231 int Memento_getBlockNum(void *b)
1232 {
1233     Memento_BlkHeader *memblk;
1234     if (b == NULL)
1235         return 0;
1236     memblk = MEMBLK_FROMBLK(b);
1237     return (memblk->sequence);
1238 }
1239 
Memento_check(void)1240 int Memento_check(void)
1241 {
1242     int result;
1243 
1244     fprintf(stderr, "Checking memory\n");
1245     result = Memento_checkAllMemory();
1246     fprintf(stderr, "Memory checked!\n");
1247     return result;
1248 }
1249 
1250 typedef struct findBlkData {
1251     void              *addr;
1252     Memento_BlkHeader *blk;
1253     int                flags;
1254 } findBlkData;
1255 
Memento_containsAddr(Memento_BlkHeader * b,void * arg)1256 static int Memento_containsAddr(Memento_BlkHeader *b,
1257                                 void *arg)
1258 {
1259     findBlkData *data = (findBlkData *)arg;
1260     char *blkend = &((char *)MEMBLK_TOBLK(b))[b->rawsize];
1261     if ((MEMBLK_TOBLK(b) <= data->addr) &&
1262         ((void *)blkend > data->addr)) {
1263         data->blk = b;
1264         data->flags = 1;
1265         return 1;
1266     }
1267     if (((void *)b <= data->addr) &&
1268         (MEMBLK_TOBLK(b) > data->addr)) {
1269         data->blk = b;
1270         data->flags = 2;
1271         return 1;
1272     }
1273     if (((void *)blkend <= data->addr) &&
1274         ((void *)(blkend + Memento_PostSize) > data->addr)) {
1275         data->blk = b;
1276         data->flags = 3;
1277         return 1;
1278     }
1279     return 0;
1280 }
1281 
Memento_find(void * a)1282 int Memento_find(void *a)
1283 {
1284     findBlkData data;
1285 
1286     data.addr  = a;
1287     data.blk   = NULL;
1288     data.flags = 0;
1289     Memento_appBlocks(&globals.used, Memento_containsAddr, &data);
1290     if (data.blk != NULL) {
1291         fprintf(stderr, "Address 0x%p is in %sallocated block ",
1292                 data.addr,
1293                 (data.flags == 1 ? "" : (data.flags == 2 ?
1294                                          "preguard of " : "postguard of ")));
1295         showBlock(data.blk, ' ');
1296         fprintf(stderr, "\n");
1297         return data.blk->sequence;
1298     }
1299     data.blk   = NULL;
1300     data.flags = 0;
1301     Memento_appBlocks(&globals.free, Memento_containsAddr, &data);
1302     if (data.blk != NULL) {
1303         fprintf(stderr, "Address 0x%p is in %sfreed block ",
1304                 data.addr,
1305                 (data.flags == 1 ? "" : (data.flags == 2 ?
1306                                          "preguard of " : "postguard of ")));
1307         showBlock(data.blk, ' ');
1308         fprintf(stderr, "\n");
1309         return data.blk->sequence;
1310     }
1311     return 0;
1312 }
1313 
Memento_breakOnFree(void * a)1314 void Memento_breakOnFree(void *a)
1315 {
1316     findBlkData data;
1317 
1318     data.addr  = a;
1319     data.blk   = NULL;
1320     data.flags = 0;
1321     Memento_appBlocks(&globals.used, Memento_containsAddr, &data);
1322     if (data.blk != NULL) {
1323         fprintf(stderr, "Will stop when address 0x%p (in %sallocated block ",
1324                 data.addr,
1325                 (data.flags == 1 ? "" : (data.flags == 2 ?
1326                                          "preguard of " : "postguard of ")));
1327         showBlock(data.blk, ' ');
1328         fprintf(stderr, ") is freed\n");
1329         data.blk->flags |= Memento_Flag_BreakOnFree;
1330         return;
1331     }
1332     data.blk   = NULL;
1333     data.flags = 0;
1334     Memento_appBlocks(&globals.free, Memento_containsAddr, &data);
1335     if (data.blk != NULL) {
1336         fprintf(stderr, "Can't stop on free; address 0x%p is in %sfreed block ",
1337                 data.addr,
1338                 (data.flags == 1 ? "" : (data.flags == 2 ?
1339                                          "preguard of " : "postguard of ")));
1340         showBlock(data.blk, ' ');
1341         fprintf(stderr, "\n");
1342         return;
1343     }
1344     fprintf(stderr, "Can't stop on free; address 0x%p is not in a known block.\n", a);
1345 }
1346 
Memento_breakOnRealloc(void * a)1347 void Memento_breakOnRealloc(void *a)
1348 {
1349     findBlkData data;
1350 
1351     data.addr  = a;
1352     data.blk   = NULL;
1353     data.flags = 0;
1354     Memento_appBlocks(&globals.used, Memento_containsAddr, &data);
1355     if (data.blk != NULL) {
1356         fprintf(stderr, "Will stop when address 0x%p (in %sallocated block ",
1357                 data.addr,
1358                 (data.flags == 1 ? "" : (data.flags == 2 ?
1359                                          "preguard of " : "postguard of ")));
1360         showBlock(data.blk, ' ');
1361         fprintf(stderr, ") is freed (or realloced)\n");
1362         data.blk->flags |= Memento_Flag_BreakOnFree | Memento_Flag_BreakOnRealloc;
1363         return;
1364     }
1365     data.blk   = NULL;
1366     data.flags = 0;
1367     Memento_appBlocks(&globals.free, Memento_containsAddr, &data);
1368     if (data.blk != NULL) {
1369         fprintf(stderr, "Can't stop on free/realloc; address 0x%p is in %sfreed block ",
1370                 data.addr,
1371                 (data.flags == 1 ? "" : (data.flags == 2 ?
1372                                          "preguard of " : "postguard of ")));
1373         showBlock(data.blk, ' ');
1374         fprintf(stderr, "\n");
1375         return;
1376     }
1377     fprintf(stderr, "Can't stop on free/realloc; address 0x%p is not in a known block.\n", a);
1378 }
1379 
Memento_failAt(int i)1380 int Memento_failAt(int i)
1381 {
1382     globals.failAt = i;
1383     if ((globals.sequence > globals.failAt) &&
1384         (globals.failing != 0))
1385         Memento_startFailing();
1386     return i;
1387 }
1388 
Memento_setMax(size_t max)1389 size_t Memento_setMax(size_t max)
1390 {
1391     globals.maxMemory = max;
1392     return max;
1393 }
1394 
1395 #else
1396 
1397 /* Just in case anyone has left some debugging code in... */
1398 void (Memento_breakpoint)(void)
1399 {
1400 }
1401 
1402 int (Memento_checkBlock)(void *b)
1403 {
1404     return 0;
1405 }
1406 
1407 int (Memento_checkAllMemory)(void)
1408 {
1409     return 0;
1410 }
1411 
1412 int (Memento_check)(void)
1413 {
1414     return 0;
1415 }
1416 
1417 int (Memento_setParanoia)(int i)
1418 {
1419     return 0;
1420 }
1421 
1422 int (Memento_paranoidAt)(int i)
1423 {
1424     return 0;
1425 }
1426 
1427 int (Memento_breakAt)(int i)
1428 {
1429     return 0;
1430 }
1431 
1432 int  (Memento_getBlockNum)(void *i)
1433 {
1434     return 0;
1435 }
1436 
1437 int (Memento_find)(void *a)
1438 {
1439     return 0;
1440 }
1441 
1442 int (Memento_failAt)(int i)
1443 {
1444     return 0;
1445 }
1446 
1447 void (Memento_breakOnFree)(void *a)
1448 {
1449 }
1450 
1451 void (Memento_breakOnRealloc)(void *a)
1452 {
1453 }
1454 
1455 #undef Memento_malloc
1456 #undef Memento_free
1457 #undef Memento_realloc
1458 #undef Memento_calloc
1459 
Memento_malloc(size_t size)1460 void *Memento_malloc(size_t size)
1461 {
1462     return MEMENTO_UNDERLYING_MALLOC(size);
1463 }
1464 
Memento_free(void * b)1465 void Memento_free(void *b)
1466 {
1467     MEMENTO_UNDERLYING_FREE(b);
1468 }
1469 
Memento_realloc(void * b,size_t s)1470 void *Memento_realloc(void *b, size_t s)
1471 {
1472     return MEMENTO_UNDERLYING_REALLOC(b, s);
1473 }
1474 
Memento_calloc(size_t n,size_t s)1475 void *Memento_calloc(size_t n, size_t s)
1476 {
1477     return MEMENTO_UNDERLYING_CALLOC(n, s);
1478 }
1479 
1480 void (Memento_listBlocks)(void)
1481 {
1482 }
1483 
1484 void (Memento_listNewBlocks)(void)
1485 {
1486 }
1487 
size_t(Memento_setMax)1488 size_t (Memento_setMax)(size_t max)
1489 {
1490     return 0;
1491 }
1492 
1493 void (Memento_stats)(void)
1494 {
1495 }
1496 
1497 void *(Memento_label)(void *ptr, const char *label)
1498 {
1499     return ptr;
1500 }
1501 
1502 #endif
1503