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