]> rtime.felk.cvut.cz Git - hornmich/skoda-qr-demo.git/blob - QRScanner/mobile/jni/thirdparty/jbig2dec/memento.c
Add MuPDF native source codes
[hornmich/skoda-qr-demo.git] / QRScanner / mobile / jni / thirdparty / jbig2dec / memento.c
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 #ifdef MEMENTO_GS_HACKS
37 /* For GS we include malloc_.h. Anyone else would just include memento.h */
38 #include "malloc_.h"
39 #ifdef __MACH__
40 #include <string.h>
41 #else
42 #ifndef memset
43 void *memset(void *,int,size_t);
44 #endif
45 #endif
46 int atexit(void (*)(void));
47 #else
48 #include "memento.h"
49 #include <stdio.h>
50 #include <stdlib.h>
51 #endif
52
53 #if defined(__linux__)
54 #define MEMENTO_HAS_FORK
55 #elif defined(__APPLE__) && defined(__MACH__)
56 #define MEMENTO_HAS_FORK
57 #endif
58
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);
64
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 *);
69
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
73
74 #ifndef MEMENTO_MAXPATTERN
75 #define MEMENTO_MAXPATTERN 0
76 #endif
77
78 #ifdef MEMENTO
79
80 #ifdef MEMENTO_GS_HACKS
81 #include "valgrind.h"
82 #else
83 #ifdef HAVE_VALGRIND
84 #include "valgrind/memcheck.h"
85 #else
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)
89 #endif
90 #endif
91
92 enum {
93     Memento_PreSize  = 16,
94     Memento_PostSize = 16
95 };
96
97 enum {
98     Memento_Flag_OldBlock = 1,
99     Memento_Flag_HasParent = 2,
100     Memento_Flag_BreakOnFree = 4,
101     Memento_Flag_BreakOnRealloc = 8
102 };
103
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 :)
110  *
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...
114  */ 
115 #ifndef MEMENTO_SEARCH_SKIP
116 #ifdef MEMENTO_GS_HACKS
117 #define MEMENTO_SEARCH_SKIP (2*sizeof(void *))
118 #else
119 #define MEMENTO_SEARCH_SKIP 0
120 #endif
121 #endif
122
123 typedef struct Memento_BlkHeader Memento_BlkHeader;
124
125 struct Memento_BlkHeader
126 {
127     size_t             rawsize;
128     int                sequence;
129     int                lastCheckedOK;
130     int                flags;
131     Memento_BlkHeader *next;
132     Memento_BlkHeader *parent; /* Only used while printing out nested list */
133
134     const char        *label;
135
136     /* Entries for nesting display calculations */
137     Memento_BlkHeader *child;
138     Memento_BlkHeader *sibling;
139
140     char               preblk[Memento_PreSize];
141 };
142
143 /* In future this could (should) be a smarter data structure, like, say,
144  * splay trees. For now, we use a list.
145  */
146 typedef struct Memento_Blocks
147 {
148     Memento_BlkHeader  *head;
149     Memento_BlkHeader **tail;
150 } Memento_Blocks;
151
152 /* And our global structure */
153 static struct {
154     int            inited;
155     Memento_Blocks used;
156     Memento_Blocks free;
157     size_t         freeListSize;
158     int            sequence;
159     int            paranoia;
160     int            paranoidAt;
161     int            countdown;
162     int            lastChecked;
163     int            breakAt;
164     int            failAt;
165     int            failing;
166     int            nextFailAt;
167     int            squeezeAt;
168     int            squeezing;
169     int            segv;
170     int            pattern;
171     int            nextPattern;
172     int            patternBit;
173     size_t         maxMemory;
174     size_t         alloc;
175     size_t         peakAlloc;
176     size_t         totalAlloc;
177     size_t         numMallocs;
178     size_t         numFrees;
179     size_t         numReallocs;
180 } globals;
181
182 #define MEMENTO_EXTRASIZE (sizeof(Memento_BlkHeader) + Memento_PostSize)
183
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))
186
187 #define MEMBLK_SIZE(s) MEMENTO_ROUNDUP(s + MEMENTO_EXTRASIZE, MEMENTO_MAXALIGN)
188
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)])
193
194 void Memento_breakpoint(void)
195 {
196     /* A handy externally visible function for breakpointing */
197 #if 0 /* Enable this to force automatic breakpointing */
198 #ifdef DEBUG
199 #ifdef _MSC_VER
200     __asm int 3;
201 #endif
202 #endif
203 #endif
204 }
205
206 static void Memento_addBlockHead(Memento_Blocks    *blks,
207                                  Memento_BlkHeader *b,
208                                  int                type)
209 {
210     if (blks->tail == &blks->head) {
211         /* Adding into an empty list, means the tail changes too */
212         blks->tail = &b->next;
213     }
214     b->next    = blks->head;
215     blks->head = b;
216 #ifndef MEMENTO_LEAKONLY
217     memset(b->preblk, MEMENTO_PREFILL, Memento_PreSize);
218     memset(MEMBLK_POSTPTR(b), MEMENTO_POSTFILL, Memento_PostSize);
219 #endif
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);
225     }
226     VALGRIND_MAKE_MEM_NOACCESS(b, sizeof(Memento_BlkHeader));
227 }
228
229 static void Memento_addBlockTail(Memento_Blocks    *blks,
230                                  Memento_BlkHeader *b,
231                                  int                type)
232 {
233     VALGRIND_MAKE_MEM_DEFINED(blks->tail, sizeof(Memento_BlkHeader *));
234     *blks->tail = b;
235     blks->tail  = &b->next;
236     b->next = NULL;
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);
241 #endif
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);
247     }
248     VALGRIND_MAKE_MEM_NOACCESS(b, sizeof(Memento_BlkHeader));
249 }
250
251 typedef struct BlkCheckData {
252     int found;
253     int preCorrupt;
254     int postCorrupt;
255     int freeCorrupt;
256     int index;
257 } BlkCheckData;
258
259 static int Memento_Internal_checkAllocedBlock(Memento_BlkHeader *b, void *arg)
260 {
261 #ifndef MEMENTO_LEAKONLY
262     int           i;
263     char         *p;
264     int           corrupt = 0;
265     BlkCheckData *data = (BlkCheckData *)arg;
266
267     p = b->preblk;
268     i = Memento_PreSize;
269     do {
270         corrupt |= (*p++ ^ (char)MEMENTO_PREFILL);
271     } while (--i);
272     if (corrupt) {
273         data->preCorrupt = 1;
274     }
275     p = MEMBLK_POSTPTR(b);
276     i = Memento_PreSize;
277     do {
278         corrupt |= (*p++ ^ (char)MEMENTO_POSTFILL);
279     } while (--i);
280     if (corrupt) {
281         data->postCorrupt = 1;
282     }
283     if ((data->freeCorrupt | data->preCorrupt | data->postCorrupt) == 0) {
284         b->lastCheckedOK = globals.sequence;
285     }
286     data->found |= 1;
287 #endif
288     return 0;
289 }
290
291 static int Memento_Internal_checkFreedBlock(Memento_BlkHeader *b, void *arg)
292 {
293 #ifndef MEMENTO_LEAKONLY
294     int           i;
295     char         *p;
296     BlkCheckData *data = (BlkCheckData *)arg;
297
298     p = MEMBLK_TOBLK(b);
299     i = b->rawsize;
300     /* Attempt to speed this up by checking an (aligned) int at a time */
301     do {
302         if (((size_t)p) & 1) {
303             if (*p++ != (char)MEMENTO_FREEFILL)
304                 break;
305             i--;
306             if (i == 0)
307                 break;
308         }
309         if ((i >= 2) && (((size_t)p) & 2)) {
310             if (*(short *)p != (short)(MEMENTO_FREEFILL | (MEMENTO_FREEFILL<<8)))
311                 goto mismatch;
312             p += 2;
313             i -= 2;
314             if (i == 0)
315                 break;
316         }
317         i -= 4;
318         while (i >= 0) {
319             if (*(int *)p != (MEMENTO_FREEFILL |
320                               (MEMENTO_FREEFILL<<8) |
321                               (MEMENTO_FREEFILL<<16) |
322                               (MEMENTO_FREEFILL<<24)))
323                 goto mismatch;
324             p += 4;
325             i -= 4;
326         }
327         i += 4;
328         if ((i >= 2) && (((size_t)p) & 2)) {
329             if (*(short *)p != (short)(MEMENTO_FREEFILL | (MEMENTO_FREEFILL<<8)))
330                 goto mismatch;
331             p += 2;
332             i -= 2;
333         }
334 mismatch:
335         while (i) {
336             if (*p++ != (char)MEMENTO_FREEFILL)
337                 break;
338             i--;
339         }
340     } while (0);
341     if (i) {
342         data->freeCorrupt = 1;
343         data->index       = b->rawsize-i;
344     }
345     return Memento_Internal_checkAllocedBlock(b, arg);
346 #else
347     return 0;
348 #endif
349 }
350
351 static void Memento_removeBlock(Memento_Blocks    *blks,
352                                 Memento_BlkHeader *b)
353 {
354     Memento_BlkHeader *head = blks->head;
355     Memento_BlkHeader *prev = NULL;
356     while ((head) && (head != b)) {
357         VALGRIND_MAKE_MEM_DEFINED(head, sizeof(*head));
358         prev = head;
359         head = head->next;
360         VALGRIND_MAKE_MEM_NOACCESS(prev, sizeof(*prev));
361     }
362     if (head == NULL) {
363         /* FAIL! Will have been reported to user earlier, so just exit. */
364         return;
365     }
366     VALGRIND_MAKE_MEM_DEFINED(blks->tail, sizeof(*blks->tail));
367     if (*blks->tail == head) {
368         /* Removing the tail of the list */
369         if (prev == NULL) {
370             /* Which is also the head */
371             blks->tail = &blks->head;
372         } else {
373             /* Which isn't the head */
374             blks->tail = &prev->next;
375         }
376     }
377     if (prev == NULL) {
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));
382     } else {
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));
389     }
390 }
391
392 static int Memento_Internal_makeSpace(size_t space)
393 {
394     /* If too big, it can never go on the freelist */
395     if (space > MEMENTO_FREELIST_MAX_SINGLE_BLOCK)
396         return 0;
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);
406     }
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;
411     return 1;
412 }
413
414 static int Memento_appBlocks(Memento_Blocks *blks,
415                              int             (*app)(Memento_BlkHeader *,
416                                                     void *),
417                              void           *arg)
418 {
419     Memento_BlkHeader *head = blks->head;
420     Memento_BlkHeader *next;
421     int                result;
422     while (head) {
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);
427         next = head->next;
428         VALGRIND_MAKE_MEM_NOACCESS(MEMBLK_POSTPTR(head), Memento_PostSize);
429         VALGRIND_MAKE_MEM_NOACCESS(head, sizeof(Memento_BlkHeader));
430         if (result)
431             return result;
432         head = next;
433     }
434     return 0;
435 }
436
437 static int Memento_appBlock(Memento_Blocks    *blks,
438                             int                (*app)(Memento_BlkHeader *,
439                                                       void *),
440                             void              *arg,
441                             Memento_BlkHeader *b)
442 {
443     Memento_BlkHeader *head = blks->head;
444     Memento_BlkHeader *next;
445     int                result;
446     while (head && head != b) {
447         VALGRIND_MAKE_MEM_DEFINED(head, sizeof(Memento_BlkHeader));
448         next = head->next;
449         VALGRIND_MAKE_MEM_NOACCESS(MEMBLK_POSTPTR(head), Memento_PostSize);
450         head = next;
451     }
452     if (head == b) {
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));
459         return result;
460     }
461     return 0;
462 }
463
464 static void showBlock(Memento_BlkHeader *b, int space)
465 {
466     fprintf(stderr, "0x%p:(size=%d,num=%d)",
467             MEMBLK_TOBLK(b), (int)b->rawsize, b->sequence);
468     if (b->label)
469         fprintf(stderr, "%c(%s)", space, b->label);
470 }
471
472 static void blockDisplay(Memento_BlkHeader *b, int n)
473 {
474     n++;
475     while(n > 0)
476     {
477         int i = n;
478         if (i > 32)
479             i = 32;
480         n -= i;
481         fprintf(stderr, "%s", &"                                "[32-i]);
482     }
483     showBlock(b, '\t');
484     fprintf(stderr, "\n");
485 }
486
487 static int Memento_listBlock(Memento_BlkHeader *b,
488                              void              *arg)
489 {
490     int *counts = (int *)arg;
491     blockDisplay(b, 0);
492     counts[0]++;
493     counts[1]+= b->rawsize;
494     return 0;
495 }
496
497 static void doNestedDisplay(Memento_BlkHeader *b,
498                             int depth)
499 {
500     blockDisplay(b, depth);
501     for (b = b->child; b; b = b->sibling)
502         doNestedDisplay(b, depth+1);
503 }
504
505 static int ptrcmp(const void *a_, const void *b_)
506 {
507     const char **a = (const char **)a_;
508     const char **b = (const char **)b_;
509     return (int)(*a-*b);
510 }
511
512 static
513 int Memento_listBlocksNested(void)
514 {
515     int count, size, i;
516     Memento_BlkHeader *b;
517     void **blocks, *minptr, *maxptr;
518     long mask;
519
520     /* Count the blocks */
521     count = 0;
522     size = 0;
523     for (b = globals.used.head; b; b = b->next) {
524         size += b->rawsize;
525         count++;
526     }
527
528     /* Make our block list */
529     blocks = MEMENTO_UNDERLYING_MALLOC(sizeof(void *) * count);
530     if (blocks == NULL)
531         return 1;
532
533     /* Populate our block list */
534     b = globals.used.head;
535     minptr = maxptr = MEMBLK_TOBLK(b);
536     mask = (long)minptr;
537     for (i = 0; b; b = b->next, i++) {
538         void *p = MEMBLK_TOBLK(b);
539         mask &= (long)p;
540         if (p < minptr)
541             minptr = p;
542         if (p > maxptr)
543             maxptr = p;
544         blocks[i] = p;
545         b->flags &= ~Memento_Flag_HasParent;
546         b->child   = NULL;
547         b->sibling = NULL;
548         b->parent  = NULL;
549     }
550     qsort(blocks, count, sizeof(void *), ptrcmp);
551
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]);
558             void **r;
559
560             /* Do trivial checks on pointer */
561             if ((mask & (int)q) != mask || q < minptr || q > maxptr)
562                 continue;
563
564             /* Search for pointer */
565             r = bsearch(&q, blocks, count, sizeof(void *), ptrcmp);
566             if (r) {
567                 /* Found child */
568                 Memento_BlkHeader *child = MEMBLK_FROMBLK(*r);
569                 Memento_BlkHeader *parent;
570
571                 /* We're assuming tree structure, not graph - ignore second
572                  * and subsequent pointers. */
573                 if (child->parent != NULL)
574                     continue;
575                 if (child->flags & Memento_Flag_HasParent)
576                     continue;
577
578                 /* We're also assuming acyclicness here. If this is one of
579                  * our parents, ignore it. */
580                 parent = b->parent;
581                 while (parent != NULL && parent != child)
582                     parent = parent->parent;
583                 if (parent == child)
584                     continue;
585
586                 child->sibling = b->child;
587                 b->child = child;
588                 child->parent = b;
589                 child->flags |= Memento_Flag_HasParent;
590             }
591         }
592     }
593
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);
598     }
599     fprintf(stderr, " Total number of blocks = %d\n", count);
600     fprintf(stderr, " Total size of blocks = %d\n", size);
601
602     MEMENTO_UNDERLYING_FREE(blocks);
603     return 0;
604 }
605
606 void Memento_listBlocks(void)
607 {
608     fprintf(stderr, "Allocated blocks:\n");
609     if (Memento_listBlocksNested())
610     {
611         int counts[2];
612         counts[0] = 0;
613         counts[1] = 0;
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]);
617     }
618 }
619
620 static int Memento_listNewBlock(Memento_BlkHeader *b,
621                                 void              *arg)
622 {
623     if (b->flags & Memento_Flag_OldBlock)
624         return 0;
625     b->flags |= Memento_Flag_OldBlock;
626     return Memento_listBlock(b, arg);
627 }
628
629 void Memento_listNewBlocks(void) {
630     int counts[2];
631     counts[0] = 0;
632     counts[1] = 0;
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]);
637 }
638
639 static void Memento_endStats(void)
640 {
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));
647 }
648
649 void Memento_stats(void)
650 {
651     fprintf(stderr, "Current memory malloced = %u bytes\n", (unsigned int)globals.alloc);
652     Memento_endStats();
653 }
654
655 static void Memento_fin(void)
656 {
657     Memento_checkAllMemory();
658     Memento_endStats();
659     if (globals.used.head != NULL) {
660         Memento_listBlocks();
661         Memento_breakpoint();
662     }
663     if (globals.segv) {
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);
668         else
669             fprintf(stderr, "Memory squeezing @ %d (%d) complete\n", globals.squeezeAt, globals.pattern);
670     }
671     if (globals.failing)
672     {
673         fprintf(stderr, "MEMENTO_FAILAT=%d\n", globals.failAt);
674         fprintf(stderr, "MEMENTO_PATTERN=%d\n", globals.pattern);
675     }
676     if (globals.nextFailAt != 0)
677     {
678         fprintf(stderr, "MEMENTO_NEXTFAILAT=%d\n", globals.nextFailAt);
679         fprintf(stderr, "MEMENTO_NEXTPATTERN=%d\n", globals.nextPattern);
680     }
681 }
682
683 static void Memento_inited(void)
684 {
685     /* A good place for a breakpoint */
686 }
687
688 static void Memento_init(void)
689 {
690     char *env;
691     memset(&globals, 0, sizeof(globals));
692     globals.inited    = 1;
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;
699
700     env = getenv("MEMENTO_FAILAT");
701     globals.failAt = (env ? atoi(env) : 0);
702
703     env = getenv("MEMENTO_PARANOIA");
704     globals.paranoia = (env ? atoi(env) : 0);
705     if (globals.paranoia == 0)
706         globals.paranoia = 1024;
707
708     env = getenv("MEMENTO_PARANOIDAT");
709     globals.paranoidAt = (env ? atoi(env) : 0);
710
711     env = getenv("MEMENTO_SQUEEZEAT");
712     globals.squeezeAt = (env ? atoi(env) : 0);
713
714     env = getenv("MEMENTO_PATTERN");
715     globals.pattern = (env ? atoi(env) : 0);
716
717     env = getenv("MEMENTO_MAXMEMORY");
718     globals.maxMemory = (env ? atoi(env) : 0);
719
720     atexit(Memento_fin);
721
722     Memento_inited();
723 }
724
725 #ifdef MEMENTO_HAS_FORK
726 #include <unistd.h>
727 #include <sys/wait.h>
728 #ifdef MEMENTO_STACKTRACE_METHOD
729 #if MEMENTO_STACKTRACE_METHOD == 1
730 #include <signal.h>
731 #endif
732 #endif
733
734 /* FIXME: Find some portable way of getting this */
735 /* MacOSX has 10240, Ubuntu seems to have 256 */
736 #define OPEN_MAX 10240
737
738 /* stashed_map[j] = i means that filedescriptor i-1 was duplicated to j */
739 int stashed_map[OPEN_MAX];
740
741 extern size_t backtrace(void **, int);
742 extern void backtrace_symbols_fd(void **, size_t, int);
743
744 static void Memento_signal(void)
745 {
746     fprintf(stderr, "SEGV after Memory squeezing @ %d\n", globals.squeezeAt);
747
748 #ifdef MEMENTO_STACKTRACE_METHOD
749 #if MEMENTO_STACKTRACE_METHOD == 1
750     {
751       void *array[100];
752       size_t size;
753
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");
759     }
760 #endif
761 #endif
762
763     exit(1);
764 }
765
766 static int squeeze(void)
767 {
768     pid_t pid;
769     int i, status;
770
771     if (globals.patternBit < 0)
772         return 1;
773     if (globals.squeezing && globals.patternBit >= MEMENTO_MAXPATTERN)
774         return 1;
775
776     if (globals.patternBit == 0)
777         globals.squeezeAt = globals.sequence;
778
779     if (!globals.squeezing) {
780         fprintf(stderr, "Memory squeezing @ %d\n", globals.squeezeAt);
781     } else
782         fprintf(stderr, "Memory squeezing @ %d (%x,%x)\n", globals.squeezeAt, globals.pattern, globals.patternBit);
783
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) {
789             int j = dup(i);
790             stashed_map[j] = i+1;
791         }
792     }
793
794     pid = fork();
795     if (pid == 0) {
796         /* Child */
797         signal(SIGSEGV, Memento_signal);
798         /* In the child, we always fail the next allocation. */
799         if (globals.patternBit == 0) {
800             globals.patternBit = 1;
801         } else
802             globals.patternBit <<= 1;
803         globals.squeezing = 1;
804         return 1;
805     }
806
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;
811
812     /* Wait for pid to finish */
813     waitpid(pid, &status, 0);
814
815     if (status != 0) {
816         fprintf(stderr, "Child status=%d\n", status);
817     }
818
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);
823             close(i);
824             stashed_map[i] = 0;
825         }
826     }
827
828     return 0;
829 }
830 #else
831 #include <signal.h>
832
833 static void Memento_signal(void)
834 {
835     globals.segv = 1;
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"))
841         exit(1);
842     else
843         Memento_fin();
844 }
845
846 int squeeze(void)
847 {
848     fprintf(stderr, "Memento memory squeezing disabled as no fork!\n");
849     return 0;
850 }
851 #endif
852
853 static void Memento_startFailing(void)
854 {
855     if (!globals.failing) {
856         fprintf(stderr, "Starting to fail...\n");
857         fflush(stderr);
858         globals.failing = 1;
859         globals.failAt = globals.sequence;
860         globals.nextFailAt = globals.sequence+1;
861         globals.pattern = 0;
862         globals.patternBit = 0;
863         signal(SIGSEGV, Memento_signal);
864         signal(SIGABRT, Memento_signal);
865         Memento_breakpoint();
866     }
867 }
868
869 static void Memento_event(void)
870 {
871     globals.sequence++;
872     if ((globals.sequence >= globals.paranoidAt) && (globals.paranoidAt != 0)) {
873         globals.paranoia = 1;
874         globals.countdown = 1;
875     }
876     if (--globals.countdown == 0) {
877         Memento_checkAllMemory();
878         globals.countdown = globals.paranoia;
879     }
880
881     if (globals.sequence == globals.breakAt) {
882         fprintf(stderr, "Breaking at event %d\n", globals.breakAt);
883         Memento_breakpoint();
884     }
885 }
886
887 int Memento_breakAt(int event)
888 {
889     globals.breakAt = event;
890     return event;
891 }
892
893 void *Memento_label(void *ptr, const char *label)
894 {
895     Memento_BlkHeader *block;
896
897     if (ptr == NULL)
898         return NULL;
899     block = MEMBLK_FROMBLK(ptr);
900     block->label = label;
901     return ptr;
902 }
903
904 int Memento_failThisEvent(void)
905 {
906     int failThisOne;
907
908     if (!globals.inited)
909         Memento_init();
910
911     Memento_event();
912
913     if ((globals.sequence >= globals.failAt) && (globals.failAt != 0))
914         Memento_startFailing();
915     if ((globals.sequence >= globals.squeezeAt) && (globals.squeezeAt != 0)) {
916         return squeeze();
917     }
918
919     if (!globals.failing)
920         return 0;
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)
929     {
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;
933     }
934     globals.patternBit = (globals.patternBit ? globals.patternBit << 1 : 1);
935
936     return failThisOne;
937 }
938
939 void *Memento_malloc(size_t s)
940 {
941     Memento_BlkHeader *memblk;
942     size_t             smem = MEMBLK_SIZE(s);
943
944     if (Memento_failThisEvent())
945         return NULL;
946
947     if (s == 0)
948         return NULL;
949
950     globals.numMallocs++;
951
952     if (globals.maxMemory != 0 && globals.alloc + s > globals.maxMemory)
953         return NULL;
954
955     memblk = MEMENTO_UNDERLYING_MALLOC(smem);
956     if (memblk == NULL)
957         return NULL;
958
959     globals.alloc      += s;
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);
965 #endif
966     memblk->rawsize       = s;
967     memblk->sequence      = globals.sequence;
968     memblk->lastCheckedOK = memblk->sequence;
969     memblk->flags         = 0;
970     memblk->label         = 0;
971     memblk->child         = NULL;
972     memblk->sibling       = NULL;
973     Memento_addBlockHead(&globals.used, memblk, 0);
974     return MEMBLK_TOBLK(memblk);
975 }
976
977 void *Memento_calloc(size_t n, size_t s)
978 {
979     void *block = Memento_malloc(n*s);
980
981     if (block)
982         memset(block, 0, n*s);
983     return block;
984 }
985
986 static int checkBlock(Memento_BlkHeader *memblk, const char *action)
987 {
988 #ifndef MEMENTO_LEAKONLY
989     BlkCheckData data;
990
991     memset(&data, 0, sizeof(data));
992     Memento_appBlock(&globals.used, Memento_Internal_checkAllocedBlock,
993                      &data, memblk);
994     if (!data.found) {
995         /* Failure! */
996         fprintf(stderr, "Attempt to %s block ", action);
997         showBlock(memblk, 32);
998         Memento_breakpoint();
999         return 1;
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");
1006         }
1007         if (data.postCorrupt) {
1008             fprintf(stderr, "Postguard corrupted\n");
1009         }
1010         fprintf(stderr, "Block last checked OK at allocation %d. Now %d.\n",
1011                 memblk->lastCheckedOK, globals.sequence);
1012         Memento_breakpoint();
1013         return 1;
1014     }
1015 #endif
1016     return 0;
1017 }
1018
1019 void Memento_free(void *blk)
1020 {
1021     Memento_BlkHeader *memblk;
1022
1023     if (!globals.inited)
1024         Memento_init();
1025
1026     Memento_event();
1027
1028     if (blk == NULL)
1029         return;
1030
1031     memblk = MEMBLK_FROMBLK(blk);
1032     VALGRIND_MAKE_MEM_DEFINED(memblk, sizeof(*memblk));
1033     if (checkBlock(memblk, "free"))
1034         return;
1035
1036     if (memblk->flags & Memento_Flag_BreakOnFree)
1037         Memento_breakpoint();
1038
1039     VALGRIND_MAKE_MEM_DEFINED(memblk, sizeof(*memblk));
1040     globals.alloc -= memblk->rawsize;
1041     globals.numFrees++;
1042
1043     Memento_removeBlock(&globals.used, memblk);
1044
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);
1052 #endif
1053         Memento_addBlockTail(&globals.free, memblk, 1);
1054     } else {
1055         MEMENTO_UNDERLYING_FREE(memblk);
1056     }
1057 }
1058
1059 void *Memento_realloc(void *blk, size_t newsize)
1060 {
1061     Memento_BlkHeader *memblk, *newmemblk;
1062     size_t             newsizemem;
1063     int                flags;
1064
1065     if (blk == NULL)
1066         return Memento_malloc(newsize);
1067     if (newsize == 0) {
1068         Memento_free(blk);
1069         return NULL;
1070     }
1071
1072     if (Memento_failThisEvent())
1073         return NULL;
1074
1075     memblk     = MEMBLK_FROMBLK(blk);
1076     if (checkBlock(memblk, "realloc"))
1077         return NULL;
1078
1079     if (memblk->flags & Memento_Flag_BreakOnRealloc)
1080         Memento_breakpoint();
1081
1082     if (globals.maxMemory != 0 && globals.alloc - memblk->rawsize + newsize > globals.maxMemory)
1083         return NULL;
1084
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)
1090     {
1091         Memento_addBlockHead(&globals.used, memblk, 2);
1092         return NULL;
1093     }
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);
1105 #endif
1106         VALGRIND_MAKE_MEM_UNDEFINED(newbytes, newsize - newmemblk->rawsize);
1107     }
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);
1112 #endif
1113     Memento_addBlockHead(&globals.used, newmemblk, 2);
1114     return MEMBLK_TOBLK(newmemblk);
1115 }
1116
1117 int Memento_checkBlock(void *blk)
1118 {
1119     Memento_BlkHeader *memblk;
1120
1121     if (blk == NULL)
1122         return 0;
1123     memblk = MEMBLK_FROMBLK(blk);
1124     return checkBlock(memblk, "check");
1125 }
1126
1127 static int Memento_Internal_checkAllAlloced(Memento_BlkHeader *memblk, void *arg)
1128 {
1129     BlkCheckData *data = (BlkCheckData *)arg;
1130
1131     Memento_Internal_checkAllocedBlock(memblk, data);
1132     if (data->preCorrupt || data->postCorrupt) {
1133         if ((data->found & 2) == 0) {
1134             fprintf(stderr, "Allocated blocks:\n");
1135             data->found |= 2;
1136         }
1137         fprintf(stderr, "  Block ");
1138         showBlock(memblk, ' ');
1139         if (data->preCorrupt) {
1140             fprintf(stderr, " Preguard ");
1141         }
1142         if (data->postCorrupt) {
1143             fprintf(stderr, "%s Postguard ",
1144                     (data->preCorrupt ? "&" : ""));
1145         }
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;
1152     }
1153     else
1154         memblk->lastCheckedOK = globals.sequence;
1155     return 0;
1156 }
1157
1158 static int Memento_Internal_checkAllFreed(Memento_BlkHeader *memblk, void *arg)
1159 {
1160     BlkCheckData *data = (BlkCheckData *)arg;
1161
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");
1166             data->found |= 4;
1167         }
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");
1175             }
1176             if (data->postCorrupt) {
1177                 fprintf(stderr, "+ postguard");
1178             }
1179         } else {
1180             if (data->preCorrupt) {
1181                 fprintf(stderr, " preguard");
1182             }
1183             if (data->postCorrupt) {
1184                 fprintf(stderr, "%s Postguard",
1185                         (data->preCorrupt ? "+" : ""));
1186             }
1187         }
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;
1194     }
1195     else
1196         memblk->lastCheckedOK = globals.sequence;
1197     return 0;
1198 }
1199
1200 int Memento_checkAllMemory(void)
1201 {
1202 #ifndef MEMENTO_LEAKONLY
1203     BlkCheckData data;
1204
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();
1210         return 1;
1211     }
1212 #endif
1213     return 0;
1214 }
1215
1216 int Memento_setParanoia(int i)
1217 {
1218     globals.paranoia = i;
1219     globals.countdown = globals.paranoia;
1220     return i;
1221 }
1222
1223 int Memento_paranoidAt(int i)
1224 {
1225     globals.paranoidAt = i;
1226     return i;
1227 }
1228
1229 int Memento_getBlockNum(void *b)
1230 {
1231     Memento_BlkHeader *memblk;
1232     if (b == NULL)
1233         return 0;
1234     memblk = MEMBLK_FROMBLK(b);
1235     return (memblk->sequence);
1236 }
1237
1238 int Memento_check(void)
1239 {
1240     int result;
1241
1242     fprintf(stderr, "Checking memory\n");
1243     result = Memento_checkAllMemory();
1244     fprintf(stderr, "Memory checked!\n");
1245     return result;
1246 }
1247
1248 typedef struct findBlkData {
1249     void              *addr;
1250     Memento_BlkHeader *blk;
1251     int                flags;
1252 } findBlkData;
1253
1254 static int Memento_containsAddr(Memento_BlkHeader *b,
1255                                 void *arg)
1256 {
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)) {
1261         data->blk = b;
1262         data->flags = 1;
1263         return 1;
1264     }
1265     if (((void *)b <= data->addr) &&
1266         (MEMBLK_TOBLK(b) > data->addr)) {
1267         data->blk = b;
1268         data->flags = 2;
1269         return 1;
1270     }
1271     if (((void *)blkend <= data->addr) &&
1272         ((void *)(blkend + Memento_PostSize) > data->addr)) {
1273         data->blk = b;
1274         data->flags = 3;
1275         return 1;
1276     }
1277     return 0;
1278 }
1279
1280 int Memento_find(void *a)
1281 {
1282     findBlkData data;
1283
1284     data.addr  = a;
1285     data.blk   = NULL;
1286     data.flags = 0;
1287     Memento_appBlocks(&globals.used, Memento_containsAddr, &data);
1288     if (data.blk != NULL) {
1289         fprintf(stderr, "Address 0x%p is in %sallocated block ",
1290                 data.addr,
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;
1296     }
1297     data.blk   = NULL;
1298     data.flags = 0;
1299     Memento_appBlocks(&globals.free, Memento_containsAddr, &data);
1300     if (data.blk != NULL) {
1301         fprintf(stderr, "Address 0x%p is in %sfreed block ",
1302                 data.addr,
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;
1308     }
1309     return 0;
1310 }
1311
1312 void Memento_breakOnFree(void *a)
1313 {
1314     findBlkData data;
1315
1316     data.addr  = a;
1317     data.blk   = NULL;
1318     data.flags = 0;
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 ",
1322                 data.addr,
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;
1328         return;
1329     }
1330     data.blk   = NULL;
1331     data.flags = 0;
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 ",
1335                 data.addr,
1336                 (data.flags == 1 ? "" : (data.flags == 2 ?
1337                                          "preguard of " : "postguard of ")));
1338         showBlock(data.blk, ' ');
1339         fprintf(stderr, "\n");
1340         return;
1341     }
1342     fprintf(stderr, "Can't stop on free; address 0x%p is not in a known block.\n", a);
1343 }
1344
1345 void Memento_breakOnRealloc(void *a)
1346 {
1347     findBlkData data;
1348
1349     data.addr  = a;
1350     data.blk   = NULL;
1351     data.flags = 0;
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 ",
1355                 data.addr,
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;
1361         return;
1362     }
1363     data.blk   = NULL;
1364     data.flags = 0;
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 ",
1368                 data.addr,
1369                 (data.flags == 1 ? "" : (data.flags == 2 ?
1370                                          "preguard of " : "postguard of ")));
1371         showBlock(data.blk, ' ');
1372         fprintf(stderr, "\n");
1373         return;
1374     }
1375     fprintf(stderr, "Can't stop on free/realloc; address 0x%p is not in a known block.\n", a);
1376 }
1377
1378 int Memento_failAt(int i)
1379 {
1380     globals.failAt = i;
1381     if ((globals.sequence > globals.failAt) &&
1382         (globals.failing != 0))
1383         Memento_startFailing();
1384     return i;
1385 }
1386
1387 size_t Memento_setMax(size_t max)
1388 {
1389     globals.maxMemory = max;
1390     return max;
1391 }
1392
1393 #else
1394
1395 /* Just in case anyone has left some debugging code in... */
1396 void (Memento_breakpoint)(void)
1397 {
1398 }
1399
1400 int (Memento_checkBlock)(void *b)
1401 {
1402     return 0;
1403 }
1404
1405 int (Memento_checkAllMemory)(void)
1406 {
1407     return 0;
1408 }
1409
1410 int (Memento_check)(void)
1411 {
1412     return 0;
1413 }
1414
1415 int (Memento_setParanoia)(int i)
1416 {
1417     return 0;
1418 }
1419
1420 int (Memento_paranoidAt)(int i)
1421 {
1422     return 0;
1423 }
1424
1425 int (Memento_breakAt)(int i)
1426 {
1427     return 0;
1428 }
1429
1430 int  (Memento_getBlockNum)(void *i)
1431 {
1432     return 0;
1433 }
1434
1435 int (Memento_find)(void *a)
1436 {
1437     return 0;
1438 }
1439
1440 int (Memento_failAt)(int i)
1441 {
1442     return 0;
1443 }
1444
1445 void (Memento_breakOnFree)(void *a)
1446 {
1447 }
1448
1449 void (Memento_breakOnRealloc)(void *a)
1450 {
1451 }
1452
1453 #undef Memento_malloc
1454 #undef Memento_free
1455 #undef Memento_realloc
1456 #undef Memento_calloc
1457
1458 void *Memento_malloc(size_t size)
1459 {
1460     return MEMENTO_UNDERLYING_MALLOC(size);
1461 }
1462
1463 void Memento_free(void *b)
1464 {
1465     MEMENTO_UNDERLYING_FREE(b);
1466 }
1467
1468 void *Memento_realloc(void *b, size_t s)
1469 {
1470     return MEMENTO_UNDERLYING_REALLOC(b, s);
1471 }
1472
1473 void *Memento_calloc(size_t n, size_t s)
1474 {
1475     return MEMENTO_UNDERLYING_CALLOC(n, s);
1476 }
1477
1478 void (Memento_listBlocks)(void)
1479 {
1480 }
1481
1482 void (Memento_listNewBlocks)(void)
1483 {
1484 }
1485
1486 size_t (Memento_setMax)(size_t max)
1487 {
1488     return 0;
1489 }
1490
1491 void (Memento_stats)(void)
1492 {
1493 }
1494
1495 void *(Memento_label)(void *ptr, const char *label)
1496 {
1497     return ptr;
1498 }
1499
1500 #endif