comparison mupdf-source/thirdparty/extract/src/memento.c @ 2:b50eed0cc0ef upstream

ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4. The directory name has changed: no version number in the expanded directory now.
author Franz Glasner <fzglas.hg@dom66.de>
date Mon, 15 Sep 2025 11:43:07 +0200
parents
children
comparison
equal deleted inserted replaced
1:1d09e1dec1d9 2:b50eed0cc0ef
1 /* Copyright (C) 2009-2020 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 COPYING in this distribution.
10
11 Refer to licensing information at http://www.artifex.com or contact
12 Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco,
13 CA 94129, USA, for further information.
14 */
15
16 /* Inspired by Fortify by Simon P Bullen. */
17
18 /* Set the following if you're only looking for leaks, not memory overwrites
19 * to speed the operation */
20 /* #define MEMENTO_LEAKONLY */
21
22 /* Set the following to keep extra details about the history of blocks */
23 #define MEMENTO_DETAILS
24
25 /* Don't keep blocks around if they'd mean losing more than a quarter of
26 * the freelist. */
27 #define MEMENTO_FREELIST_MAX_SINGLE_BLOCK (MEMENTO_FREELIST_MAX/4)
28
29 #define COMPILING_MEMENTO_C
30
31 /* SHUT UP, MSVC. I KNOW WHAT I AM DOING. */
32 #define _CRT_SECURE_NO_WARNINGS
33
34 /* We have some GS specific tweaks; more for the GS build environment than
35 * anything else. */
36 /* #define MEMENTO_GS_HACKS */
37
38 #ifdef MEMENTO_GS_HACKS
39 /* For GS we include malloc_.h. Anyone else would just include memento.h */
40 #include "malloc_.h"
41 #include "memory_.h"
42 int atexit(void (*)(void));
43 #else
44 #ifdef MEMENTO_MUPDF_HACKS
45 #include "mupdf/memento.h"
46 #else
47 #include "memento.h"
48 #endif
49 #include <stdio.h>
50 #endif
51 #ifndef _MSC_VER
52 #include <stdint.h>
53 #include <limits.h>
54 #include <unistd.h>
55 #endif
56
57 #include <errno.h>
58 #include <stdlib.h>
59 #include <stdarg.h>
60 #include <string.h>
61
62 #ifdef __ANDROID__
63 #define MEMENTO_ANDROID
64 #include <stdio.h>
65 #endif
66
67 /* Hacks to portably print large sizes */
68 #ifdef _MSC_VER
69 #define FMTZ "%llu"
70 #define FMTZ_CAST _int64
71 #define FMTP "0x%p"
72 #else
73 #define FMTZ "%zu"
74 #define FMTZ_CAST size_t
75 #define FMTP "%p"
76 #endif
77
78 #define UB(x) ((intptr_t)((x) & 0xFF))
79 #define B2I(x) (UB(x) | (UB(x)<<8) | (UB(x)<<16) | (UB(x)<<24))
80 #define B2P(x) ((void *)(B2I(x) | ((B2I(x)<<16)<<16)))
81 #define MEMENTO_PREFILL_UBYTE ((unsigned char)(MEMENTO_PREFILL))
82 #define MEMENTO_PREFILL_USHORT (((unsigned short)MEMENTO_PREFILL_UBYTE) | (((unsigned short)MEMENTO_PREFILL_UBYTE)<<8))
83 #define MEMENTO_PREFILL_UINT (((unsigned int)MEMENTO_PREFILL_USHORT) | (((unsigned int)MEMENTO_PREFILL_USHORT)<<16))
84 #define MEMENTO_PREFILL_PTR (void *)(((uintptr_t)MEMENTO_PREFILL_UINT) | ((((uintptr_t)MEMENTO_PREFILL_UINT)<<16)<<16))
85 #define MEMENTO_POSTFILL_UBYTE ((unsigned char)(MEMENTO_POSTFILL))
86 #define MEMENTO_POSTFILL_USHORT (((unsigned short)MEMENTO_POSTFILL_UBYTE) | (((unsigned short)MEMENTO_POSTFILL_UBYTE)<<8))
87 #define MEMENTO_POSTFILL_UINT (((unsigned int)MEMENTO_POSTFILL_USHORT) | (((unsigned int)MEMENTO_POSTFILL_USHORT)<<16))
88 #define MEMENTO_POSTFILL_PTR (void *)(((uintptr_t)MEMENTO_POSTFILL_UINT) | ((((uintptr_t)MEMENTO_POSTFILL_UINT)<<16)<<16))
89 #define MEMENTO_ALLOCFILL_UBYTE ((unsigned char)(MEMENTO_ALLOCFILL))
90 #define MEMENTO_ALLOCFILL_USHORT (((unsigned short)MEMENTO_ALLOCFILL_UBYTE) | (((unsigned short)MEMENTO_ALLOCFILL_UBYTE)<<8))
91 #define MEMENTO_ALLOCFILL_UINT (((unsigned int)MEMENTO_ALLOCFILL_USHORT) | (((unsigned int)MEMENTO_ALLOCFILL_USHORT)<<16))
92 #define MEMENTO_ALLOCFILL_PTR (void *)(((uintptr_t)MEMENTO_ALLOCFILL_UINT) | ((((uintptr_t)MEMENTO_ALLOCFILL_UINT)<<16)<<16))
93 #define MEMENTO_FREEFILL_UBYTE ((unsigned char)(MEMENTO_FREEFILL))
94 #define MEMENTO_FREEFILL_USHORT (((unsigned short)MEMENTO_FREEFILL_UBYTE) | (((unsigned short)MEMENTO_FREEFILL_UBYTE)<<8))
95 #define MEMENTO_FREEFILL_UINT (((unsigned int)MEMENTO_FREEFILL_USHORT) | (((unsigned int)MEMENTO_FREEFILL_USHORT)<<16))
96 #define MEMENTO_FREEFILL_PTR (void *)(((uintptr_t)MEMENTO_FREEFILL_UINT) | ((((uintptr_t)MEMENTO_FREEFILL_UINT)<<16)<<16))
97
98 #ifdef MEMENTO
99
100 #ifndef MEMENTO_CPP_EXTRAS_ONLY
101
102 #ifdef MEMENTO_ANDROID
103 #include <android/log.h>
104
105 static char log_buffer[4096];
106 static int log_fill = 0;
107
108 static char log_buffer2[4096];
109
110 static int
111 android_fprintf(FILE *file, const char *fmt, ...)
112 {
113 va_list args;
114 char *p, *q;
115
116 va_start(args, fmt);
117 vsnprintf(log_buffer2, sizeof(log_buffer2)-1, fmt, args);
118 va_end(args);
119
120 /* Ensure we are always null terminated */
121 log_buffer2[sizeof(log_buffer2)-1] = 0;
122
123 p = log_buffer2;
124 q = p;
125 do
126 {
127 /* Find the end of the string, or the next \n */
128 while (*p && *p != '\n')
129 p++;
130
131 /* We need to output from q to p. Limit ourselves to what
132 * will fit in the existing */
133 if (p - q >= sizeof(log_buffer)-1 - log_fill)
134 p = q + sizeof(log_buffer)-1 - log_fill;
135
136 memcpy(&log_buffer[log_fill], q, p-q);
137 log_fill += p-q;
138 if (*p == '\n')
139 {
140 log_buffer[log_fill] = 0;
141 __android_log_print(ANDROID_LOG_ERROR, "memento", "%s", log_buffer);
142 usleep(1);
143 log_fill = 0;
144 p++; /* Skip over the \n */
145 }
146 else if (log_fill >= sizeof(log_buffer)-1)
147 {
148 log_buffer[sizeof(log_buffer2)-1] = 0;
149 __android_log_print(ANDROID_LOG_ERROR, "memento", "%s", log_buffer);
150 usleep(1);
151 log_fill = 0;
152 }
153 q = p;
154 }
155 while (*p);
156
157 return 0;
158 }
159
160 #define fprintf android_fprintf
161 #define MEMENTO_STACKTRACE_METHOD 3
162 #endif
163
164 /* _WIN64 defined implies _WIN32 will be */
165 #ifdef _WIN32
166 #include <windows.h>
167
168 static int
169 windows_fprintf(FILE *file, const char *fmt, ...)
170 {
171 va_list args;
172 char text[4096];
173 int ret;
174
175 va_start(args, fmt);
176 ret = vfprintf(file, fmt, args);
177 va_end(args);
178
179 va_start(args, fmt);
180 vsnprintf(text, 4096, fmt, args);
181 OutputDebugStringA(text);
182 va_end(args);
183
184 return ret;
185 }
186
187 #define fprintf windows_fprintf
188 #endif
189
190 #ifndef MEMENTO_STACKTRACE_METHOD
191 #ifdef __GNUC__
192 #define MEMENTO_STACKTRACE_METHOD 1
193 #endif
194 #ifdef _WIN32
195 #define MEMENTO_STACKTRACE_METHOD 2
196 #endif
197 #endif
198
199 #if defined(__linux__) || defined(__OpenBSD__)
200 #define MEMENTO_HAS_FORK
201 #elif defined(__APPLE__) && defined(__MACH__)
202 #define MEMENTO_HAS_FORK
203 #endif
204
205 /* Define the underlying allocators, just in case */
206 void *MEMENTO_UNDERLYING_MALLOC(size_t);
207 void MEMENTO_UNDERLYING_FREE(void *);
208 void *MEMENTO_UNDERLYING_REALLOC(void *,size_t);
209 void *MEMENTO_UNDERLYING_CALLOC(size_t,size_t);
210
211 /* And some other standard functions we use. We don't include the header
212 * files, just in case they pull in unexpected others. */
213 int atoi(const char *);
214 char *getenv(const char *);
215
216 /* How far to search for pointers in each block when calculating nestings */
217 /* mupdf needs at least 34000ish (sizeof(fz_shade))/ */
218 #define MEMENTO_PTRSEARCH 65536
219
220 #ifndef MEMENTO_MAXPATTERN
221 #define MEMENTO_MAXPATTERN 0
222 #endif
223
224 #ifdef MEMENTO_GS_HACKS
225 #include "valgrind.h"
226 #else
227 #ifdef HAVE_VALGRIND
228 #include "valgrind/memcheck.h"
229 #else
230 #define VALGRIND_MAKE_MEM_NOACCESS(p,s) do { } while (0==1)
231 #define VALGRIND_MAKE_MEM_UNDEFINED(p,s) do { } while (0==1)
232 #define VALGRIND_MAKE_MEM_DEFINED(p,s) do { } while (0==1)
233 #endif
234 #endif
235
236 enum {
237 Memento_PreSize = 16,
238 Memento_PostSize = 16
239 };
240
241 /* Some compile time checks */
242 typedef struct
243 {
244 char MEMENTO_PRESIZE_MUST_BE_A_MULTIPLE_OF_4[Memento_PreSize & 3 ? -1 : 1];
245 char MEMENTO_POSTSIZE_MUST_BE_A_MULTIPLE_OF_4[Memento_PostSize & 3 ? -1 : 1];
246 char MEMENTO_POSTSIZE_MUST_BE_AT_LEAST_4[Memento_PostSize >= 4 ? 1 : -1];
247 char MEMENTO_PRESIZE_MUST_BE_AT_LEAST_4[Memento_PreSize >= 4 ? 1 : -1];
248 } MEMENTO_SANITY_CHECK_STRUCT;
249
250 #define MEMENTO_UINT32 unsigned int
251 #define MEMENTO_UINT16 unsigned short
252
253 #define MEMENTO_PREFILL_UINT32 ((MEMENTO_UINT32)(MEMENTO_PREFILL | (MEMENTO_PREFILL <<8) | (MEMENTO_PREFILL <<16) |(MEMENTO_PREFILL <<24)))
254 #define MEMENTO_POSTFILL_UINT16 ((MEMENTO_UINT16)(MEMENTO_POSTFILL | (MEMENTO_POSTFILL<<8)))
255 #define MEMENTO_POSTFILL_UINT32 ((MEMENTO_UINT32)(MEMENTO_POSTFILL | (MEMENTO_POSTFILL<<8) | (MEMENTO_POSTFILL<<16) |(MEMENTO_POSTFILL<<24)))
256 #define MEMENTO_FREEFILL_UINT16 ((MEMENTO_UINT16)(MEMENTO_FREEFILL | (MEMENTO_FREEFILL<<8)))
257 #define MEMENTO_FREEFILL_UINT32 ((MEMENTO_UINT32)(MEMENTO_FREEFILL | (MEMENTO_FREEFILL<<8) | (MEMENTO_FREEFILL<<16) |(MEMENTO_FREEFILL<<24)))
258
259 enum {
260 Memento_Flag_OldBlock = 1,
261 Memento_Flag_HasParent = 2,
262 Memento_Flag_BreakOnFree = 4,
263 Memento_Flag_BreakOnRealloc = 8,
264 Memento_Flag_Freed = 16,
265 Memento_Flag_KnownLeak = 32,
266 Memento_Flag_Reported = 64
267 };
268
269 enum {
270 Memento_EventType_malloc = 0,
271 Memento_EventType_calloc = 1,
272 Memento_EventType_realloc = 2,
273 Memento_EventType_free = 3,
274 Memento_EventType_new = 4,
275 Memento_EventType_delete = 5,
276 Memento_EventType_newArray = 6,
277 Memento_EventType_deleteArray = 7,
278 Memento_EventType_takeRef = 8,
279 Memento_EventType_dropRef = 9,
280 Memento_EventType_reference = 10,
281 Memento_EventType_strdup = 11,
282 Memento_EventType_asprintf = 12,
283 Memento_EventType_vasprintf = 13
284 };
285
286 static const char *eventType[] =
287 {
288 "malloc",
289 "calloc",
290 "realloc",
291 "free",
292 "new",
293 "delete",
294 "new[]",
295 "delete[]",
296 "takeRef",
297 "dropRef",
298 "reference",
299 "strdup",
300 "asprintf",
301 "vasprintf"
302 };
303
304 /* When we list leaked blocks at the end of execution, we search for pointers
305 * between blocks in order to be able to give a nice nested view.
306 * Unfortunately, if you have are running your own allocator (such as
307 * postscript's chunk allocator) you can often find that the header of the
308 * block always contains pointers to next or previous blocks. This tends to
309 * mean the nesting displayed is "uninteresting" at best :)
310 *
311 * As a hack to get around this, we have a define MEMENTO_SKIP_SEARCH that
312 * indicates how many bytes to skip over at the start of the chunk.
313 * This may cause us to miss true nestings, but such is life...
314 */
315 #ifndef MEMENTO_SEARCH_SKIP
316 #ifdef MEMENTO_GS_HACKS
317 #define MEMENTO_SEARCH_SKIP (2*sizeof(void *))
318 #else
319 #define MEMENTO_SEARCH_SKIP 0
320 #endif
321 #endif
322
323 #define MEMENTO_CHILD_MAGIC ((Memento_BlkHeader *)('M' | ('3' << 8) | ('m' << 16) | ('3' << 24)))
324 #define MEMENTO_SIBLING_MAGIC ((Memento_BlkHeader *)('n' | ('t' << 8) | ('0' << 16) | ('!' << 24)))
325
326 #ifdef MEMENTO_DETAILS
327 typedef struct Memento_BlkDetails Memento_BlkDetails;
328
329 struct Memento_BlkDetails
330 {
331 Memento_BlkDetails *next;
332 char type;
333 char count;
334 int sequence;
335 void *stack[1];
336 };
337 #endif /* MEMENTO_DETAILS */
338
339 typedef struct Memento_BlkHeader Memento_BlkHeader;
340
341 struct Memento_BlkHeader
342 {
343 size_t rawsize;
344 int sequence;
345 int lastCheckedOK;
346 int flags;
347 Memento_BlkHeader *next;
348 Memento_BlkHeader *prev; /* Reused as 'parent' when printing nested list */
349
350 const char *label;
351
352 /* Entries for nesting display calculations. Set to magic
353 * values at all other time. */
354 Memento_BlkHeader *child;
355 Memento_BlkHeader *sibling;
356
357 #ifdef MEMENTO_DETAILS
358 Memento_BlkDetails *details;
359 Memento_BlkDetails **details_tail;
360 #endif
361
362 char preblk[Memento_PreSize];
363 };
364
365 /* In future this could (should) be a smarter data structure, like, say,
366 * splay trees. For now, we use a list.
367 */
368 typedef struct Memento_Blocks
369 {
370 Memento_BlkHeader *head;
371 Memento_BlkHeader *tail;
372 } Memento_Blocks;
373
374 /* What sort of Mutex should we use? */
375 #ifdef MEMENTO_LOCKLESS
376 typedef int Memento_mutex;
377
378 static void Memento_initMutex(Memento_mutex *m)
379 {
380 (void)m;
381 }
382
383 #define MEMENTO_DO_LOCK() do { } while (0)
384 #define MEMENTO_DO_UNLOCK() do { } while (0)
385
386 #else
387 #if defined(_WIN32) || defined(_WIN64)
388 /* Windows */
389 typedef CRITICAL_SECTION Memento_mutex;
390
391 static void Memento_initMutex(Memento_mutex *m)
392 {
393 InitializeCriticalSection(m);
394 }
395
396 #define MEMENTO_DO_LOCK() \
397 EnterCriticalSection(&memento.mutex)
398 #define MEMENTO_DO_UNLOCK() \
399 LeaveCriticalSection(&memento.mutex)
400
401 #else
402 #include <pthread.h>
403 typedef pthread_mutex_t Memento_mutex;
404
405 static void Memento_initMutex(Memento_mutex *m)
406 {
407 pthread_mutex_init(m, NULL);
408 }
409
410 #define MEMENTO_DO_LOCK() \
411 pthread_mutex_lock(&memento.mutex)
412 #define MEMENTO_DO_UNLOCK() \
413 pthread_mutex_unlock(&memento.mutex)
414
415 #endif
416 #endif
417
418 typedef struct {
419 int begin;
420 int end;
421 } Memento_range;
422
423 /* And our global structure */
424 static struct {
425 int inited;
426 Memento_Blocks used;
427 Memento_Blocks free;
428 size_t freeListSize;
429 int sequence;
430 int paranoia;
431 int paranoidAt;
432 int countdown;
433 int lastChecked;
434 int breakAt;
435 int failAt;
436 int failing;
437 int nextFailAt;
438 int squeezeAt;
439 int squeezing;
440 int segv;
441 int pattern;
442 int nextPattern;
443 int patternBit;
444 int leaking;
445 int hideMultipleReallocs;
446 int abortOnLeak;
447 int abortOnCorruption;
448 size_t maxMemory;
449 size_t alloc;
450 size_t peakAlloc;
451 size_t totalAlloc;
452 size_t numMallocs;
453 size_t numFrees;
454 size_t numReallocs;
455 Memento_mutex mutex;
456 Memento_range *squeezes;
457 int squeezes_num;
458 int squeezes_pos;
459 } memento;
460
461 #define MEMENTO_EXTRASIZE (sizeof(Memento_BlkHeader) + Memento_PostSize)
462
463 /* Round up size S to the next multiple of N (where N is a power of 2) */
464 #define MEMENTO_ROUNDUP(S,N) ((S + N-1)&~(N-1))
465
466 #define MEMBLK_SIZE(s) MEMENTO_ROUNDUP(s + MEMENTO_EXTRASIZE, MEMENTO_MAXALIGN)
467
468 #define MEMBLK_FROMBLK(B) (&((Memento_BlkHeader*)(void *)(B))[-1])
469 #define MEMBLK_TOBLK(B) ((void*)(&((Memento_BlkHeader*)(void*)(B))[1]))
470 #define MEMBLK_POSTPTR(B) \
471 (&((unsigned char *)(void *)(B))[(B)->rawsize + sizeof(Memento_BlkHeader)])
472
473 enum
474 {
475 SkipStackBackTraceLevels = 4
476 };
477
478 #if defined(MEMENTO_STACKTRACE_METHOD) && MEMENTO_STACKTRACE_METHOD == 1
479 extern size_t backtrace(void **, int);
480 extern void backtrace_symbols_fd(void **, size_t, int);
481 extern char **backtrace_symbols(void **, size_t);
482
483 #define MEMENTO_BACKTRACE_MAX 256
484 static void (*print_stack_value)(void *address);
485
486 /* Libbacktrace gubbins - relies on us having libdl to load the .so */
487 #ifdef HAVE_LIBDL
488 #include <dlfcn.h>
489
490 typedef void (*backtrace_error_callback) (void *data, const char *msg, int errnum);
491
492 typedef struct backtrace_state *(*backtrace_create_state_type)(
493 const char *filename, int threaded,
494 backtrace_error_callback error_callback, void *data);
495
496 typedef int (*backtrace_full_callback) (void *data, uintptr_t pc,
497 const char *filename, int lineno,
498 const char *function);
499
500 typedef int (*backtrace_pcinfo_type)(struct backtrace_state *state,
501 uintptr_t pc,
502 backtrace_full_callback callback,
503 backtrace_error_callback error_callback,
504 void *data);
505
506 typedef void (*backtrace_syminfo_callback) (void *data, uintptr_t pc,
507 const char *symname,
508 uintptr_t symval,
509 uintptr_t symsize);
510
511 typedef int (*backtrace_syminfo_type)(struct backtrace_state *state,
512 uintptr_t addr,
513 backtrace_syminfo_callback callback,
514 backtrace_error_callback error_callback,
515 void *data);
516
517 static backtrace_syminfo_type backtrace_syminfo;
518 static backtrace_create_state_type backtrace_create_state;
519 static backtrace_pcinfo_type backtrace_pcinfo;
520 static struct backtrace_state *my_backtrace_state;
521 static void *libbt;
522 static char backtrace_exe[4096];
523 static void *current_addr;
524
525 static void error2_cb(void *data, const char *msg, int errnum)
526 {
527 (void)data;
528 (void)msg;
529 (void)errnum;
530 }
531
532 static void syminfo_cb(void *data, uintptr_t pc, const char *symname, uintptr_t symval, uintptr_t symsize)
533 {
534 (void)data;
535 (void)symval;
536 (void)symsize;
537 if (sizeof(void *) == 4)
538 fprintf(stderr, " 0x%08lx %s\n", pc, symname?symname:"?");
539 else
540 fprintf(stderr, " 0x%016lx %s\n", pc, symname?symname:"?");
541 }
542
543 static void error_cb(void *data, const char *msg, int errnum)
544 {
545 (void)data;
546 (void)msg;
547 (void)errnum;
548 backtrace_syminfo(my_backtrace_state,
549 (uintptr_t)current_addr,
550 syminfo_cb,
551 error2_cb,
552 NULL);
553 }
554
555 static int full_cb(void *data, uintptr_t pc, const char *fname, int line, const char *fn)
556 {
557 (void)data;
558 if (sizeof(void *) == 4)
559 fprintf(stderr, " 0x%08lx %s(%s:%d)\n", pc, fn?fn:"?", fname?fname:"?", line);
560 else
561 fprintf(stderr, " 0x%016lx %s(%s:%d)\n", pc, fn?fn:"?", fname?fname:"?", line);
562 return 0;
563 }
564
565 static void print_stack_libbt(void *addr)
566 {
567 current_addr = addr;
568 backtrace_pcinfo(my_backtrace_state,
569 (uintptr_t)addr,
570 full_cb,
571 error_cb,
572 NULL);
573 }
574
575 static void print_stack_libbt_failed(void *addr)
576 {
577 char **strings;
578 #if 0
579 /* Let's use a hack from Julian Smith to call gdb to extract the information */
580 /* Disabled for now, as I can't make this work. */
581 static char command[1024];
582 int e;
583 static int gdb_invocation_failed = 0;
584
585 if (gdb_invocation_failed == 0)
586 {
587 snprintf(command, sizeof(command),
588 //"gdb -q --batch -p=%i -ex 'info line *%p' -ex quit 2>/dev/null",
589 "gdb -q --batch -p=%i -ex 'info line *%p' -ex quit 2>/dev/null| egrep -v '(Thread debugging using)|(Using host libthread_db library)|(A debugging session is active)|(will be detached)|(Quit anyway)|(No such file or directory)|(^0x)|(^$)'",
590 getpid(), addr);
591 printf("%s\n", command);
592 e = system(command);
593 if (e == 0)
594 return; /* That'll do! */
595 gdb_invocation_failed = 1; /* If it's failed once, it'll probably keep failing. */
596 }
597 #endif
598
599 /* We couldn't even get gdb! Make do. */
600 strings = backtrace_symbols(&addr, 1);
601
602 if (strings == NULL || strings[0] == NULL)
603 {
604 if (sizeof(void *) == 4)
605 fprintf(stderr, " [0x%08lx]\n", (uintptr_t)addr);
606 else
607 fprintf(stderr, " [0x%016lx]\n", (uintptr_t)addr);
608 }
609 else
610 {
611 fprintf(stderr, " %s\n", strings[0]);
612 }
613 (free)(strings);
614 }
615
616 static int init_libbt(void)
617 {
618 static int libbt_inited = 0;
619
620 if (libbt_inited)
621 return 0;
622 libbt_inited = 1;
623
624 libbt = dlopen("libbacktrace.so", RTLD_LAZY);
625 if (libbt == NULL)
626 libbt = dlopen("/opt/lib/libbacktrace.so", RTLD_LAZY);
627 if (libbt == NULL)
628 libbt = dlopen("/lib/libbacktrace.so", RTLD_LAZY);
629 if (libbt == NULL)
630 libbt = dlopen("/usr/lib/libbacktrace.so", RTLD_LAZY);
631 if (libbt == NULL)
632 libbt = dlopen("/usr/local/lib/libbacktrace.so", RTLD_LAZY);
633 if (libbt == NULL)
634 goto fail;
635
636 backtrace_create_state = dlsym(libbt, "backtrace_create_state");
637 backtrace_syminfo = dlsym(libbt, "backtrace_syminfo");
638 backtrace_pcinfo = dlsym(libbt, "backtrace_pcinfo");
639
640 if (backtrace_create_state == NULL ||
641 backtrace_syminfo == NULL ||
642 backtrace_pcinfo == NULL)
643 {
644 goto fail;
645 }
646
647 my_backtrace_state = backtrace_create_state(backtrace_exe,
648 1 /*BACKTRACE_SUPPORTS_THREADS*/,
649 error_cb,
650 NULL);
651 if (my_backtrace_state == NULL)
652 goto fail;
653
654 print_stack_value = print_stack_libbt;
655
656 return 1;
657
658 fail:
659 fprintf(stderr,
660 "MEMENTO: libbacktrace.so failed to load; backtraces will be sparse.\n"
661 "MEMENTO: See memento.h for how to rectify this.\n");
662 libbt = NULL;
663 backtrace_create_state = NULL;
664 backtrace_syminfo = NULL;
665 print_stack_value = print_stack_libbt_failed;
666 return 0;
667 }
668 #endif
669
670 static void print_stack_default(void *addr)
671 {
672 char **strings = backtrace_symbols(&addr, 1);
673
674 if (strings == NULL || strings[0] == NULL)
675 {
676 fprintf(stderr, " ["FMTP"]\n", addr);
677 }
678 #ifdef HAVE_LIBDL
679 else if (strchr(strings[0], ':') == NULL)
680 {
681 /* Probably a "path [address]" format string */
682 char *s = strchr(strings[0], ' ');
683
684 if (s != strings[0])
685 {
686 memcpy(backtrace_exe, strings[0], s - strings[0]);
687 backtrace_exe[s-strings[0]] = 0;
688 init_libbt();
689 print_stack_value(addr);
690 }
691 }
692 #endif
693 else
694 {
695 fprintf(stderr, " %s\n", strings[0]);
696 }
697 free(strings);
698 }
699
700 static void Memento_initStacktracer(void)
701 {
702 print_stack_value = print_stack_default;
703 }
704
705 static int Memento_getStacktrace(void **stack, int *skip)
706 {
707 size_t num;
708
709 num = backtrace(&stack[0], MEMENTO_BACKTRACE_MAX);
710
711 *skip = SkipStackBackTraceLevels;
712 if (num <= SkipStackBackTraceLevels)
713 return 0;
714 return (int)(num-SkipStackBackTraceLevels);
715 }
716
717 static void Memento_showStacktrace(void **stack, int numberOfFrames)
718 {
719 int i;
720
721 for (i = 0; i < numberOfFrames; i++)
722 {
723 print_stack_value(stack[i]);
724 }
725 }
726 #elif defined(MEMENTO_STACKTRACE_METHOD) && MEMENTO_STACKTRACE_METHOD == 2
727 #include <Windows.h>
728
729 /* We use DbgHelp.dll rather than DbgHelp.lib. This avoids us needing
730 * extra link time complications, and enables us to fall back gracefully
731 * if the DLL cannot be found.
732 *
733 * To achieve this we have our own potted versions of the required types
734 * inline here.
735 */
736 #ifdef _WIN64
737 typedef DWORD64 DWORD_NATIVESIZED;
738 #else
739 typedef DWORD DWORD_NATIVESIZED;
740 #endif
741
742 #define MEMENTO_BACKTRACE_MAX 64
743
744 typedef USHORT (__stdcall *My_CaptureStackBackTraceType)(__in ULONG, __in ULONG, __out PVOID*, __out_opt PULONG);
745
746 typedef struct MY_IMAGEHLP_LINE {
747 DWORD SizeOfStruct;
748 PVOID Key;
749 DWORD LineNumber;
750 PCHAR FileName;
751 DWORD_NATIVESIZED Address;
752 } MY_IMAGEHLP_LINE, *MY_PIMAGEHLP_LINE;
753
754 typedef BOOL (__stdcall *My_SymGetLineFromAddrType)(HANDLE hProcess, DWORD_NATIVESIZED dwAddr, PDWORD pdwDisplacement, MY_PIMAGEHLP_LINE Line);
755
756 typedef struct MY_SYMBOL_INFO {
757 ULONG SizeOfStruct;
758 ULONG TypeIndex; // Type Index of symbol
759 ULONG64 Reserved[2];
760 ULONG info;
761 ULONG Size;
762 ULONG64 ModBase; // Base Address of module containing this symbol
763 ULONG Flags;
764 ULONG64 Value; // Value of symbol, ValuePresent should be 1
765 ULONG64 Address; // Address of symbol including base address of module
766 ULONG Register; // register holding value or pointer to value
767 ULONG Scope; // scope of the symbol
768 ULONG Tag; // pdb classification
769 ULONG NameLen; // Actual length of name
770 ULONG MaxNameLen;
771 CHAR Name[1]; // Name of symbol
772 } MY_SYMBOL_INFO, *MY_PSYMBOL_INFO;
773
774 typedef BOOL (__stdcall *My_SymFromAddrType)(HANDLE hProcess, DWORD64 Address, PDWORD64 Displacement, MY_PSYMBOL_INFO Symbol);
775 typedef BOOL (__stdcall *My_SymInitializeType)(HANDLE hProcess, PSTR UserSearchPath, BOOL fInvadeProcess);
776
777 static My_CaptureStackBackTraceType Memento_CaptureStackBackTrace;
778 static My_SymGetLineFromAddrType Memento_SymGetLineFromAddr;
779 static My_SymFromAddrType Memento_SymFromAddr;
780 static My_SymInitializeType Memento_SymInitialize;
781 static HANDLE Memento_process;
782
783 static void Memento_initStacktracer(void)
784 {
785 HMODULE mod = LoadLibrary("kernel32.dll");
786
787 if (mod == NULL)
788 return;
789 Memento_CaptureStackBackTrace = (My_CaptureStackBackTraceType)(GetProcAddress(mod, "RtlCaptureStackBackTrace"));
790 if (Memento_CaptureStackBackTrace == NULL)
791 return;
792 mod = LoadLibrary("Dbghelp.dll");
793 if (mod == NULL) {
794 Memento_CaptureStackBackTrace = NULL;
795 return;
796 }
797 Memento_SymGetLineFromAddr =
798 (My_SymGetLineFromAddrType)(GetProcAddress(mod,
799 #ifdef _WIN64
800 "SymGetLineFromAddr64"
801 #else
802 "SymGetLineFromAddr"
803 #endif
804 ));
805 if (Memento_SymGetLineFromAddr == NULL) {
806 Memento_CaptureStackBackTrace = NULL;
807 return;
808 }
809 Memento_SymFromAddr = (My_SymFromAddrType)(GetProcAddress(mod, "SymFromAddr"));
810 if (Memento_SymFromAddr == NULL) {
811 Memento_CaptureStackBackTrace = NULL;
812 return;
813 }
814 Memento_SymInitialize = (My_SymInitializeType)(GetProcAddress(mod, "SymInitialize"));
815 if (Memento_SymInitialize == NULL) {
816 Memento_CaptureStackBackTrace = NULL;
817 return;
818 }
819 Memento_process = GetCurrentProcess();
820 Memento_SymInitialize(Memento_process, NULL, TRUE);
821 }
822
823 static int Memento_getStacktrace(void **stack, int *skip)
824 {
825 if (Memento_CaptureStackBackTrace == NULL)
826 return 0;
827
828 *skip = 0;
829 /* Limit us to 63 levels due to windows bug */
830 return Memento_CaptureStackBackTrace(SkipStackBackTraceLevels, 63-SkipStackBackTraceLevels, stack, NULL);
831 }
832
833 static void Memento_showStacktrace(void **stack, int numberOfFrames)
834 {
835 MY_IMAGEHLP_LINE line;
836 int i;
837 char symbol_buffer[sizeof(MY_SYMBOL_INFO) + 1024 + 1];
838 MY_SYMBOL_INFO *symbol = (MY_SYMBOL_INFO *)symbol_buffer;
839
840 symbol->MaxNameLen = 1024;
841 symbol->SizeOfStruct = sizeof(MY_SYMBOL_INFO);
842 line.SizeOfStruct = sizeof(MY_IMAGEHLP_LINE);
843 for (i = 0; i < numberOfFrames; i++)
844 {
845 DWORD64 dwDisplacement64;
846 DWORD dwDisplacement;
847 Memento_SymFromAddr(Memento_process, (DWORD64)(stack[i]), &dwDisplacement64, symbol);
848 Memento_SymGetLineFromAddr(Memento_process, (DWORD_NATIVESIZED)(stack[i]), &dwDisplacement, &line);
849 fprintf(stderr, " %s in %s:%d\n", symbol->Name, line.FileName, line.LineNumber);
850 }
851 }
852 #elif defined(MEMENTO_STACKTRACE_METHOD) && MEMENTO_STACKTRACE_METHOD == 3
853
854 #include <unwind.h>
855 #include <dlfcn.h>
856
857 /* From cxxabi.h */
858 extern char* __cxa_demangle(const char* mangled_name,
859 char* output_buffer,
860 size_t* length,
861 int* status);
862
863 static void Memento_initStacktracer(void)
864 {
865 }
866
867 #define MEMENTO_BACKTRACE_MAX 256
868
869 typedef struct
870 {
871 int count;
872 void **addr;
873 } my_unwind_details;
874
875 static _Unwind_Reason_Code unwind_populate_callback(struct _Unwind_Context *context,
876 void *arg)
877 {
878 my_unwind_details *uw = (my_unwind_details *)arg;
879 int count = uw->count;
880
881 if (count >= MEMENTO_BACKTRACE_MAX)
882 return _URC_END_OF_STACK;
883
884 uw->addr[count] = (void *)_Unwind_GetIP(context);
885 uw->count++;
886
887 return _URC_NO_REASON;
888 }
889
890 static int Memento_getStacktrace(void **stack, int *skip)
891 {
892 my_unwind_details uw = { 0, stack };
893
894 *skip = 0;
895
896 /* Collect the backtrace. Deliberately only unwind once,
897 * and avoid using malloc etc until this completes just
898 * in case. */
899 _Unwind_Backtrace(unwind_populate_callback, &uw);
900 if (uw.count <= SkipStackBackTraceLevels)
901 return 0;
902
903 *skip = SkipStackBackTraceLevels;
904 return uw.count-SkipStackBackTraceLevels;
905 }
906
907 static void Memento_showStacktrace(void **stack, int numberOfFrames)
908 {
909 int i;
910
911 for (i = 0; i < numberOfFrames; i++)
912 {
913 Dl_info info;
914 if (dladdr(stack[i], &info))
915 {
916 int status = 0;
917 const char *sym = info.dli_sname ? info.dli_sname : "<unknown>";
918 char *demangled = __cxa_demangle(sym, NULL, 0, &status);
919 int offset = stack[i] - info.dli_saddr;
920 fprintf(stderr, " ["FMTP"]%s(+0x%x)\n", stack[i], demangled && status == 0 ? demangled : sym, offset);
921 free(demangled);
922 }
923 else
924 {
925 fprintf(stderr, " ["FMTP"]\n", stack[i]);
926 }
927 }
928 }
929
930 #else
931 static void Memento_initStacktracer(void)
932 {
933 }
934
935 static int Memento_getStacktrace(void **stack, int *skip)
936 {
937 *skip = 0;
938 return 0;
939 }
940
941 static void Memento_showStacktrace(void **stack, int numberOfFrames)
942 {
943 }
944 #endif /* MEMENTO_STACKTRACE_METHOD */
945
946 #ifdef MEMENTO_DETAILS
947 static void Memento_storeDetails(Memento_BlkHeader *head, int type)
948 {
949 void *stack[MEMENTO_BACKTRACE_MAX];
950 Memento_BlkDetails *details;
951 int count;
952 int skip;
953
954 if (head == NULL)
955 return;
956
957 #ifdef MEMENTO_STACKTRACE_METHOD
958 count = Memento_getStacktrace(stack, &skip);
959 #else
960 skip = 0;
961 count = 0;
962 #endif
963
964 details = MEMENTO_UNDERLYING_MALLOC(sizeof(*details) + (count-1) * sizeof(void *));
965 if (details == NULL)
966 return;
967
968 if (count)
969 memcpy(&details->stack, &stack[skip], count * sizeof(void *));
970
971 details->type = (char)type;
972 details->count = (char)count;
973 details->sequence = memento.sequence;
974 details->next = NULL;
975 VALGRIND_MAKE_MEM_DEFINED(&head->details_tail, sizeof(head->details_tail));
976 *head->details_tail = details;
977 head->details_tail = &details->next;
978 VALGRIND_MAKE_MEM_NOACCESS(&head->details_tail, sizeof(head->details_tail));
979 }
980 #endif
981
982 void (Memento_bt)(void)
983 {
984 #ifdef MEMENTO_STACKTRACE_METHOD
985 void *stack[MEMENTO_BACKTRACE_MAX];
986 int count;
987 int skip;
988
989 count = Memento_getStacktrace(stack, &skip);
990 Memento_showStacktrace(&stack[skip-2], count-skip+2);
991 #endif
992 }
993
994 static void Memento_bt_internal(int skip2)
995 {
996 #ifdef MEMENTO_STACKTRACE_METHOD
997 void *stack[MEMENTO_BACKTRACE_MAX];
998 int count;
999 int skip;
1000
1001 count = Memento_getStacktrace(stack, &skip);
1002 Memento_showStacktrace(&stack[skip+skip2], count-skip-skip2);
1003 #endif
1004 }
1005
1006 static int Memento_checkAllMemoryLocked(void);
1007
1008 void Memento_breakpoint(void)
1009 {
1010 /* A handy externally visible function for breakpointing */
1011 #if 0 /* Enable this to force automatic breakpointing */
1012 #ifndef NDEBUG
1013 #ifdef _MSC_VER
1014 __asm int 3;
1015 #endif
1016 #endif
1017 #endif
1018 }
1019
1020 static void Memento_init(void);
1021
1022 #define MEMENTO_LOCK() \
1023 do { if (!memento.inited) Memento_init(); MEMENTO_DO_LOCK(); } while (0)
1024
1025 #define MEMENTO_UNLOCK() \
1026 do { MEMENTO_DO_UNLOCK(); } while (0)
1027
1028 /* Do this as a macro to prevent another level in the callstack,
1029 * which is annoying while stepping. */
1030 #define Memento_breakpointLocked() \
1031 do { MEMENTO_UNLOCK(); Memento_breakpoint(); MEMENTO_LOCK(); } while (0)
1032
1033 static void Memento_addBlockHead(Memento_Blocks *blks,
1034 Memento_BlkHeader *b,
1035 int type)
1036 {
1037 if (blks->tail == NULL)
1038 blks->tail = b;
1039 b->next = blks->head;
1040 b->prev = NULL;
1041 if (blks->head)
1042 {
1043 VALGRIND_MAKE_MEM_DEFINED(&blks->head->prev, sizeof(blks->head->prev));
1044 blks->head->prev = b;
1045 VALGRIND_MAKE_MEM_NOACCESS(&blks->head->prev, sizeof(blks->head->prev));
1046 }
1047 blks->head = b;
1048 #ifndef MEMENTO_LEAKONLY
1049 memset(b->preblk, MEMENTO_PREFILL, Memento_PreSize);
1050 memset(MEMBLK_POSTPTR(b), MEMENTO_POSTFILL, Memento_PostSize);
1051 #endif
1052 VALGRIND_MAKE_MEM_NOACCESS(MEMBLK_POSTPTR(b), Memento_PostSize);
1053 if (type == 0) { /* malloc */
1054 VALGRIND_MAKE_MEM_UNDEFINED(MEMBLK_TOBLK(b), b->rawsize);
1055 } else if (type == 1) { /* free */
1056 VALGRIND_MAKE_MEM_NOACCESS(MEMBLK_TOBLK(b), b->rawsize);
1057 }
1058 VALGRIND_MAKE_MEM_NOACCESS(b, sizeof(Memento_BlkHeader));
1059 }
1060
1061 static void Memento_addBlockTail(Memento_Blocks *blks,
1062 Memento_BlkHeader *b,
1063 int type)
1064 {
1065 VALGRIND_MAKE_MEM_DEFINED(&blks->tail, sizeof(Memento_BlkHeader *));
1066 if (blks->head == NULL)
1067 blks->head = b;
1068 b->prev = blks->tail;
1069 b->next = NULL;
1070 if (blks->tail) {
1071 VALGRIND_MAKE_MEM_DEFINED(&blks->tail->next, sizeof(blks->tail->next));
1072 blks->tail->next = b;
1073 VALGRIND_MAKE_MEM_NOACCESS(&blks->tail->next, sizeof(blks->tail->next));
1074 }
1075 blks->tail = b;
1076 #ifndef MEMENTO_LEAKONLY
1077 memset(b->preblk, MEMENTO_PREFILL, Memento_PreSize);
1078 memset(MEMBLK_POSTPTR(b), MEMENTO_POSTFILL, Memento_PostSize);
1079 #endif
1080 VALGRIND_MAKE_MEM_NOACCESS(MEMBLK_POSTPTR(b), Memento_PostSize);
1081 if (type == 0) { /* malloc */
1082 VALGRIND_MAKE_MEM_UNDEFINED(MEMBLK_TOBLK(b), b->rawsize);
1083 } else if (type == 1) { /* free */
1084 VALGRIND_MAKE_MEM_NOACCESS(MEMBLK_TOBLK(b), b->rawsize);
1085 }
1086 VALGRIND_MAKE_MEM_NOACCESS(b, sizeof(Memento_BlkHeader));
1087 VALGRIND_MAKE_MEM_NOACCESS(&blks->tail, sizeof(Memento_BlkHeader *));
1088 }
1089
1090 typedef struct BlkCheckData {
1091 int found;
1092 int preCorrupt;
1093 int postCorrupt;
1094 int freeCorrupt;
1095 size_t index;
1096 } BlkCheckData;
1097
1098 #ifndef MEMENTO_LEAKONLY
1099 static int Memento_Internal_checkAllocedBlock(Memento_BlkHeader *b, void *arg)
1100 {
1101 int i;
1102 MEMENTO_UINT32 *ip;
1103 unsigned char *p;
1104 BlkCheckData *data = (BlkCheckData *)arg;
1105
1106 ip = (MEMENTO_UINT32 *)(void *)(b->preblk);
1107 i = Memento_PreSize>>2;
1108 do {
1109 if (*ip++ != MEMENTO_PREFILL_UINT32)
1110 goto pre_corrupt;
1111 } while (--i);
1112 if (0) {
1113 pre_corrupt:
1114 data->preCorrupt = 1;
1115 }
1116 /* Postfill may not be aligned, so have to be slower */
1117 p = MEMBLK_POSTPTR(b);
1118 i = Memento_PostSize-4;
1119 if ((intptr_t)p & 1)
1120 {
1121 if (*p++ != MEMENTO_POSTFILL)
1122 goto post_corrupt;
1123 i--;
1124 }
1125 if ((intptr_t)p & 2)
1126 {
1127 if (*(MEMENTO_UINT16 *)p != MEMENTO_POSTFILL_UINT16)
1128 goto post_corrupt;
1129 p += 2;
1130 i -= 2;
1131 }
1132 do {
1133 if (*(MEMENTO_UINT32 *)p != MEMENTO_POSTFILL_UINT32)
1134 goto post_corrupt;
1135 p += 4;
1136 i -= 4;
1137 } while (i >= 0);
1138 if (i & 2)
1139 {
1140 if (*(MEMENTO_UINT16 *)p != MEMENTO_POSTFILL_UINT16)
1141 goto post_corrupt;
1142 p += 2;
1143 }
1144 if (i & 1)
1145 {
1146 if (*p != MEMENTO_POSTFILL)
1147 goto post_corrupt;
1148 }
1149 if (0) {
1150 post_corrupt:
1151 data->postCorrupt = 1;
1152 }
1153 if ((data->freeCorrupt | data->preCorrupt | data->postCorrupt) == 0) {
1154 b->lastCheckedOK = memento.sequence;
1155 }
1156 data->found |= 1;
1157 return 0;
1158 }
1159
1160 static int Memento_Internal_checkFreedBlock(Memento_BlkHeader *b, void *arg)
1161 {
1162 size_t i;
1163 unsigned char *p;
1164 BlkCheckData *data = (BlkCheckData *)arg;
1165
1166 p = MEMBLK_TOBLK(b); /* p will always be aligned */
1167 i = b->rawsize;
1168 /* Attempt to speed this up by checking an (aligned) int at a time */
1169 if (i >= 4) {
1170 i -= 4;
1171 do {
1172 if (*(MEMENTO_UINT32 *)p != MEMENTO_FREEFILL_UINT32)
1173 goto mismatch4;
1174 p += 4;
1175 i -= 4;
1176 } while (i > 0);
1177 i += 4;
1178 }
1179 if (i & 2) {
1180 if (*(MEMENTO_UINT16 *)p != MEMENTO_FREEFILL_UINT16)
1181 goto mismatch;
1182 p += 2;
1183 i -= 2;
1184 }
1185 if (0) {
1186 mismatch4:
1187 i += 4;
1188 }
1189 mismatch:
1190 while (i) {
1191 if (*p++ != (unsigned char)MEMENTO_FREEFILL)
1192 break;
1193 i--;
1194 }
1195 if (i) {
1196 data->freeCorrupt = 1;
1197 data->index = b->rawsize-i;
1198 }
1199 return Memento_Internal_checkAllocedBlock(b, arg);
1200 }
1201 #endif /* MEMENTO_LEAKONLY */
1202
1203 static void Memento_removeBlock(Memento_Blocks *blks,
1204 Memento_BlkHeader *b)
1205 {
1206 VALGRIND_MAKE_MEM_DEFINED(b, sizeof(*b));
1207 if (b->next) {
1208 VALGRIND_MAKE_MEM_DEFINED(&b->next->prev, sizeof(b->next->prev));
1209 b->next->prev = b->prev;
1210 VALGRIND_MAKE_MEM_NOACCESS(&b->next->prev, sizeof(b->next->prev));
1211 }
1212 if (b->prev) {
1213 VALGRIND_MAKE_MEM_DEFINED(&b->prev->next, sizeof(b->prev->next));
1214 b->prev->next = b->next;
1215 VALGRIND_MAKE_MEM_NOACCESS(&b->prev->next, sizeof(b->prev->next));
1216 }
1217 if (blks->tail == b)
1218 blks->tail = b->prev;
1219 if (blks->head == b)
1220 blks->head = b->next;
1221 }
1222
1223 static void free_block(Memento_BlkHeader *head)
1224 {
1225 #ifdef MEMENTO_DETAILS
1226 Memento_BlkDetails *details = head->details;
1227
1228 while (details)
1229 {
1230 Memento_BlkDetails *next = details->next;
1231 MEMENTO_UNDERLYING_FREE(details);
1232 details = next;
1233 }
1234 #endif
1235 MEMENTO_UNDERLYING_FREE(head);
1236 }
1237
1238 static int Memento_Internal_makeSpace(size_t space)
1239 {
1240 /* If too big, it can never go on the freelist */
1241 if (space > MEMENTO_FREELIST_MAX_SINGLE_BLOCK)
1242 return 0;
1243 /* Pretend we added it on. */
1244 memento.freeListSize += space;
1245 /* Ditch blocks until it fits within our limit */
1246 while (memento.freeListSize > MEMENTO_FREELIST_MAX) {
1247 Memento_BlkHeader *head = memento.free.head;
1248 VALGRIND_MAKE_MEM_DEFINED(head, sizeof(*head));
1249 memento.free.head = head->next;
1250 memento.freeListSize -= MEMBLK_SIZE(head->rawsize);
1251 free_block(head);
1252 }
1253 /* Make sure we haven't just completely emptied the free list */
1254 /* (This should never happen, but belt and braces... */
1255 if (memento.free.head == NULL)
1256 memento.free.tail = NULL;
1257 return 1;
1258 }
1259
1260 static int Memento_appBlocks(Memento_Blocks *blks,
1261 int (*app)(Memento_BlkHeader *,
1262 void *),
1263 void *arg)
1264 {
1265 Memento_BlkHeader *head = blks->head;
1266 Memento_BlkHeader *next;
1267 int result;
1268 while (head) {
1269 VALGRIND_MAKE_MEM_DEFINED(head, sizeof(Memento_BlkHeader));
1270 VALGRIND_MAKE_MEM_DEFINED(MEMBLK_TOBLK(head),
1271 head->rawsize + Memento_PostSize);
1272 result = app(head, arg);
1273 next = head->next;
1274 VALGRIND_MAKE_MEM_NOACCESS(MEMBLK_POSTPTR(head), Memento_PostSize);
1275 VALGRIND_MAKE_MEM_NOACCESS(head, sizeof(Memento_BlkHeader));
1276 if (result)
1277 return result;
1278 head = next;
1279 }
1280 return 0;
1281 }
1282
1283 #ifndef MEMENTO_LEAKONLY
1284 /* Distrustful - check the block is a real one */
1285 static int Memento_appBlockUser(Memento_Blocks *blks,
1286 int (*app)(Memento_BlkHeader *,
1287 void *),
1288 void *arg,
1289 Memento_BlkHeader *b)
1290 {
1291 Memento_BlkHeader *head = blks->head;
1292 Memento_BlkHeader *next;
1293 int result;
1294 while (head && head != b) {
1295 VALGRIND_MAKE_MEM_DEFINED(head, sizeof(Memento_BlkHeader));
1296 next = head->next;
1297 VALGRIND_MAKE_MEM_NOACCESS(MEMBLK_POSTPTR(head), Memento_PostSize);
1298 head = next;
1299 }
1300 if (head == b) {
1301 VALGRIND_MAKE_MEM_DEFINED(head, sizeof(Memento_BlkHeader));
1302 VALGRIND_MAKE_MEM_DEFINED(MEMBLK_TOBLK(head),
1303 head->rawsize + Memento_PostSize);
1304 result = app(head, arg);
1305 VALGRIND_MAKE_MEM_NOACCESS(MEMBLK_POSTPTR(head), Memento_PostSize);
1306 VALGRIND_MAKE_MEM_NOACCESS(head, sizeof(Memento_BlkHeader));
1307 return result;
1308 }
1309 return 0;
1310 }
1311
1312 static int Memento_appBlock(Memento_Blocks *blks,
1313 int (*app)(Memento_BlkHeader *,
1314 void *),
1315 void *arg,
1316 Memento_BlkHeader *b)
1317 {
1318 int result;
1319 (void)blks;
1320 VALGRIND_MAKE_MEM_DEFINED(b, sizeof(Memento_BlkHeader));
1321 VALGRIND_MAKE_MEM_DEFINED(MEMBLK_TOBLK(b),
1322 b->rawsize + Memento_PostSize);
1323 result = app(b, arg);
1324 VALGRIND_MAKE_MEM_NOACCESS(MEMBLK_POSTPTR(b), Memento_PostSize);
1325 VALGRIND_MAKE_MEM_NOACCESS(b, sizeof(Memento_BlkHeader));
1326 return result;
1327 }
1328 #endif /* MEMENTO_LEAKONLY */
1329
1330 static int showBlock(Memento_BlkHeader *b, int space)
1331 {
1332 int seq;
1333 VALGRIND_MAKE_MEM_DEFINED(b, sizeof(Memento_BlkHeader));
1334 fprintf(stderr, FMTP":(size=" FMTZ ",num=%d)",
1335 MEMBLK_TOBLK(b), (FMTZ_CAST)b->rawsize, b->sequence);
1336 if (b->label)
1337 fprintf(stderr, "%c(%s)", space, b->label);
1338 if (b->flags & Memento_Flag_KnownLeak)
1339 fprintf(stderr, "(Known Leak)");
1340 seq = b->sequence;
1341 VALGRIND_MAKE_MEM_NOACCESS(b, sizeof(Memento_BlkHeader));
1342 return seq;
1343 }
1344
1345 static void blockDisplay(Memento_BlkHeader *b, int n)
1346 {
1347 n++;
1348 while (n > 40)
1349 {
1350 fprintf(stderr, "*");
1351 n -= 40;
1352 }
1353 while(n > 0)
1354 {
1355 int i = n;
1356 if (i > 32)
1357 i = 32;
1358 n -= i;
1359 fprintf(stderr, "%s", &" "[32-i]);
1360 }
1361 showBlock(b, '\t');
1362 fprintf(stderr, "\n");
1363 }
1364
1365 static int Memento_listBlock(Memento_BlkHeader *b,
1366 void *arg)
1367 {
1368 size_t *counts = (size_t *)arg;
1369 blockDisplay(b, 0);
1370 counts[0]++;
1371 VALGRIND_MAKE_MEM_DEFINED(b, sizeof(Memento_BlkHeader));
1372 counts[1]+= b->rawsize;
1373 VALGRIND_MAKE_MEM_NOACCESS(b, sizeof(Memento_BlkHeader));
1374 return 0;
1375 }
1376
1377 static void doNestedDisplay(Memento_BlkHeader *b,
1378 int depth)
1379 {
1380 /* Try and avoid recursion if we can help it */
1381 do {
1382 Memento_BlkHeader *c = NULL;
1383 blockDisplay(b, depth);
1384 VALGRIND_MAKE_MEM_DEFINED(b, sizeof(Memento_BlkHeader));
1385 if (b->sibling) {
1386 c = b->child;
1387 b = b->sibling;
1388 } else {
1389 b = b->child;
1390 depth++;
1391 }
1392 VALGRIND_MAKE_MEM_NOACCESS(b, sizeof(Memento_BlkHeader));
1393 if (c)
1394 doNestedDisplay(c, depth+1);
1395 } while (b);
1396 }
1397
1398 static int ptrcmp(const void *a_, const void *b_)
1399 {
1400 const char **a = (const char **)a_;
1401 const char **b = (const char **)b_;
1402 return (int)(*a-*b);
1403 }
1404
1405 static
1406 int Memento_listBlocksNested(void)
1407 {
1408 int count, i;
1409 size_t size;
1410 Memento_BlkHeader *b, *prev;
1411 void **blocks, *minptr, *maxptr;
1412 intptr_t mask;
1413
1414 /* Count the blocks */
1415 count = 0;
1416 size = 0;
1417 for (b = memento.used.head; b; b = b->next) {
1418 VALGRIND_MAKE_MEM_DEFINED(b, sizeof(*b));
1419 size += b->rawsize;
1420 count++;
1421 }
1422
1423 /* Make our block list */
1424 blocks = MEMENTO_UNDERLYING_MALLOC(sizeof(void *) * count);
1425 if (blocks == NULL)
1426 return 1;
1427
1428 /* Populate our block list */
1429 b = memento.used.head;
1430 minptr = maxptr = MEMBLK_TOBLK(b);
1431 mask = (intptr_t)minptr;
1432 for (i = 0; b; b = b->next, i++) {
1433 void *p = MEMBLK_TOBLK(b);
1434 mask &= (intptr_t)p;
1435 if (p < minptr)
1436 minptr = p;
1437 if (p > maxptr)
1438 maxptr = p;
1439 blocks[i] = p;
1440 b->flags &= ~Memento_Flag_HasParent;
1441 b->child = NULL;
1442 b->sibling = NULL;
1443 b->prev = NULL; /* parent */
1444 }
1445 qsort(blocks, count, sizeof(void *), ptrcmp);
1446
1447 /* Now, calculate tree */
1448 for (b = memento.used.head; b; b = b->next) {
1449 char *p = MEMBLK_TOBLK(b);
1450 size_t end = (b->rawsize < MEMENTO_PTRSEARCH ? b->rawsize : MEMENTO_PTRSEARCH);
1451 size_t z;
1452 VALGRIND_MAKE_MEM_DEFINED(p, end);
1453 if (end > sizeof(void *)-1)
1454 end -= sizeof(void *)-1;
1455 else
1456 end = 0;
1457 for (z = MEMENTO_SEARCH_SKIP; z < end; z += sizeof(void *)) {
1458 void *q = *(void **)(&p[z]);
1459 void **r;
1460
1461 /* Do trivial checks on pointer */
1462 if ((mask & (intptr_t)q) != mask || q < minptr || q > maxptr)
1463 continue;
1464
1465 /* Search for pointer */
1466 r = bsearch(&q, blocks, count, sizeof(void *), ptrcmp);
1467 if (r) {
1468 /* Found child */
1469 Memento_BlkHeader *child = MEMBLK_FROMBLK(*r);
1470 Memento_BlkHeader *parent;
1471
1472 /* We're assuming tree structure, not graph - ignore second
1473 * and subsequent pointers. */
1474 if (child->prev != NULL) /* parent */
1475 continue;
1476 if (child->flags & Memento_Flag_HasParent)
1477 continue;
1478
1479 /* Not interested in pointers to ourself! */
1480 if (child == b)
1481 continue;
1482
1483 /* We're also assuming acyclicness here. If this is one of
1484 * our parents, ignore it. */
1485 parent = b->prev; /* parent */
1486 while (parent != NULL && parent != child)
1487 parent = parent->prev; /* parent */
1488 if (parent == child)
1489 continue;
1490
1491 child->sibling = b->child;
1492 b->child = child;
1493 child->prev = b; /* parent */
1494 child->flags |= Memento_Flag_HasParent;
1495 }
1496 }
1497 }
1498
1499 /* Now display with nesting */
1500 for (b = memento.used.head; b; b = b->next) {
1501 if ((b->flags & Memento_Flag_HasParent) == 0)
1502 doNestedDisplay(b, 0);
1503 }
1504 fprintf(stderr, " Total number of blocks = %d\n", count);
1505 fprintf(stderr, " Total size of blocks = "FMTZ"\n", (FMTZ_CAST)size);
1506
1507 MEMENTO_UNDERLYING_FREE(blocks);
1508
1509 /* Now put the blocks back for valgrind, and restore the prev
1510 * and magic values. */
1511 prev = NULL;
1512 for (b = memento.used.head; b;) {
1513 Memento_BlkHeader *next = b->next;
1514 b->prev = prev;
1515 b->child = MEMENTO_CHILD_MAGIC;
1516 b->sibling = MEMENTO_SIBLING_MAGIC;
1517 prev = b;
1518 VALGRIND_MAKE_MEM_NOACCESS(b, sizeof(*b));
1519 b = next;
1520 }
1521
1522 return 0;
1523 }
1524
1525 void Memento_listBlocks(void)
1526 {
1527 MEMENTO_LOCK();
1528 fprintf(stderr, "Allocated blocks:\n");
1529 if (Memento_listBlocksNested())
1530 {
1531 size_t counts[2];
1532 counts[0] = 0;
1533 counts[1] = 0;
1534 Memento_appBlocks(&memento.used, Memento_listBlock, &counts[0]);
1535 fprintf(stderr, " Total number of blocks = "FMTZ"\n", (FMTZ_CAST)counts[0]);
1536 fprintf(stderr, " Total size of blocks = "FMTZ"\n", (FMTZ_CAST)counts[1]);
1537 }
1538 MEMENTO_UNLOCK();
1539 }
1540
1541 static int Memento_listNewBlock(Memento_BlkHeader *b,
1542 void *arg)
1543 {
1544 if (b->flags & Memento_Flag_OldBlock)
1545 return 0;
1546 b->flags |= Memento_Flag_OldBlock;
1547 return Memento_listBlock(b, arg);
1548 }
1549
1550 void Memento_listNewBlocks(void)
1551 {
1552 size_t counts[2];
1553 MEMENTO_LOCK();
1554 counts[0] = 0;
1555 counts[1] = 0;
1556 fprintf(stderr, "Blocks allocated and still extant since last list:\n");
1557 Memento_appBlocks(&memento.used, Memento_listNewBlock, &counts[0]);
1558 fprintf(stderr, " Total number of blocks = "FMTZ"\n", (FMTZ_CAST)counts[0]);
1559 fprintf(stderr, " Total size of blocks = "FMTZ"\n", (FMTZ_CAST)counts[1]);
1560 MEMENTO_UNLOCK();
1561 }
1562
1563 static void Memento_endStats(void)
1564 {
1565 fprintf(stderr, "Total memory malloced = "FMTZ" bytes\n", (FMTZ_CAST)memento.totalAlloc);
1566 fprintf(stderr, "Peak memory malloced = "FMTZ" bytes\n", (FMTZ_CAST)memento.peakAlloc);
1567 fprintf(stderr, FMTZ" mallocs, "FMTZ" frees, "FMTZ" reallocs\n", (FMTZ_CAST)memento.numMallocs,
1568 (FMTZ_CAST)memento.numFrees, (FMTZ_CAST)memento.numReallocs);
1569 fprintf(stderr, "Average allocation size "FMTZ" bytes\n", (FMTZ_CAST)
1570 (memento.numMallocs != 0 ? memento.totalAlloc/memento.numMallocs: 0));
1571 }
1572
1573 void Memento_stats(void)
1574 {
1575 MEMENTO_LOCK();
1576 fprintf(stderr, "Current memory malloced = "FMTZ" bytes\n", (FMTZ_CAST)memento.alloc);
1577 Memento_endStats();
1578 MEMENTO_UNLOCK();
1579 }
1580
1581 #ifdef MEMENTO_DETAILS
1582 static int showInfo(Memento_BlkHeader *b, void *arg)
1583 {
1584 Memento_BlkDetails *details;
1585
1586 (void)arg;
1587
1588 fprintf(stderr, FMTP":(size="FMTZ",num=%d)",
1589 MEMBLK_TOBLK(b), (FMTZ_CAST)b->rawsize, b->sequence);
1590 if (b->label)
1591 fprintf(stderr, " (%s)", b->label);
1592 fprintf(stderr, "\nEvents:\n");
1593
1594 for (details = b->details; details; details = details->next)
1595 {
1596 if (memento.hideMultipleReallocs &&
1597 details->type == Memento_EventType_realloc &&
1598 details->next &&
1599 details->next->type == Memento_EventType_realloc) {
1600 continue;
1601 }
1602 fprintf(stderr, " Event %d (%s)\n", details->sequence, eventType[(int)details->type]);
1603 Memento_showStacktrace(details->stack, details->count);
1604 }
1605 return 0;
1606 }
1607 #endif
1608
1609 void Memento_listBlockInfo(void)
1610 {
1611 #ifdef MEMENTO_DETAILS
1612 MEMENTO_LOCK();
1613 fprintf(stderr, "Details of allocated blocks:\n");
1614 Memento_appBlocks(&memento.used, showInfo, NULL);
1615 MEMENTO_UNLOCK();
1616 #endif
1617 }
1618
1619 static int Memento_nonLeakBlocksLeaked(void)
1620 {
1621 Memento_BlkHeader *blk = memento.used.head;
1622 while (blk)
1623 {
1624 Memento_BlkHeader *next;
1625 int leaked;
1626 VALGRIND_MAKE_MEM_DEFINED(blk, sizeof(*blk));
1627 leaked = ((blk->flags & Memento_Flag_KnownLeak) == 0);
1628 next = blk->next;
1629 VALGRIND_MAKE_MEM_DEFINED(blk, sizeof(*blk));
1630 if (leaked)
1631 return 1;
1632 blk = next;
1633 }
1634 return 0;
1635 }
1636
1637 void Memento_fin(void)
1638 {
1639 Memento_checkAllMemory();
1640 if (!memento.segv)
1641 {
1642 Memento_endStats();
1643 if (Memento_nonLeakBlocksLeaked()) {
1644 Memento_listBlocks();
1645 #ifdef MEMENTO_DETAILS
1646 fprintf(stderr, "\n");
1647 Memento_listBlockInfo();
1648 #endif
1649 Memento_breakpoint();
1650 }
1651 }
1652 if (memento.squeezing) {
1653 if (memento.pattern == 0)
1654 fprintf(stderr, "Memory squeezing @ %d complete%s\n", memento.squeezeAt, memento.segv ? " (with SEGV)" : "");
1655 else
1656 fprintf(stderr, "Memory squeezing @ %d (%d) complete%s\n", memento.squeezeAt, memento.pattern, memento.segv ? " (with SEGV)" : "");
1657 } else if (memento.segv) {
1658 fprintf(stderr, "Memento completed (with SEGV)\n");
1659 }
1660 if (memento.failing)
1661 {
1662 fprintf(stderr, "MEMENTO_FAILAT=%d\n", memento.failAt);
1663 fprintf(stderr, "MEMENTO_PATTERN=%d\n", memento.pattern);
1664 }
1665 if (memento.nextFailAt != 0)
1666 {
1667 fprintf(stderr, "MEMENTO_NEXTFAILAT=%d\n", memento.nextFailAt);
1668 fprintf(stderr, "MEMENTO_NEXTPATTERN=%d\n", memento.nextPattern);
1669 }
1670 if (Memento_nonLeakBlocksLeaked() && memento.abortOnLeak) {
1671 fprintf(stderr, "Calling abort() because blocks were leaked and MEMENTO_ABORT_ON_LEAK is set.\n");
1672 abort();
1673 }
1674 }
1675
1676 /* Reads number from <text> using strtol().
1677 *
1678 * Params:
1679 * text:
1680 * text to read.
1681 * out:
1682 * pointer to output value.
1683 * relative:
1684 * *relative set to 1 if <text> starts with '+' or '-', else set to 0.
1685 * end:
1686 * *end is set to point to next unread character after number.
1687 *
1688 * Returns 0 on success, else -1.
1689 */
1690 static int read_number(const char *text, int *out, int *relative, char **end)
1691 {
1692 if (text[0] == '+' || text[0] == '-')
1693 *relative = 1;
1694 else
1695 *relative = 0;
1696 errno = 0;
1697 *out = (int)strtol(text, end, 0 /*base*/);
1698 if (errno || *end == text)
1699 {
1700 fprintf(stderr, "Failed to parse number at start of '%s'.\n", text);
1701 return -1;
1702 }
1703 if (0)
1704 fprintf(stderr, "text='%s': *out=%i *relative=%i\n",
1705 text, *out, *relative);
1706 return 0;
1707 }
1708
1709 /* Reads number plus optional delta value from <text>.
1710 *
1711 * Evaluates <number> or <number>[+|-<delta>]. E.g. text='1234+2' sets *out=1236,
1712 * text='1234-1' sets *out=1233.
1713 *
1714 * Params:
1715 * text:
1716 * text to read.
1717 * out:
1718 * pointer to output value.
1719 * end:
1720 * *end is set to point to next unread character after number.
1721 *
1722 * Returns 0 on success, else -1.
1723 */
1724 static int read_number_delta(const char *text, int *out, char **end)
1725 {
1726 int e;
1727 int relative;
1728
1729 e = read_number(text, out, &relative, end);
1730 if (e)
1731 return e;
1732 if (relative) {
1733 fprintf(stderr, "Base number should not start with '+' or '-' at start of '%s'.\n",
1734 text);
1735 return -1;
1736 }
1737 if (*end) {
1738 if (**end == '-' || **end == '+') {
1739 int delta;
1740 e = read_number(*end, &delta, &relative, end);
1741 if (e)
1742 return e;
1743 *out += delta;
1744 }
1745 }
1746 if (0) fprintf(stderr, "text='%s': *out=%i\n", text, *out);
1747
1748 return 0;
1749 }
1750
1751 /* Reads range.
1752 *
1753 * E.g.:
1754 * text='115867-2' sets *begin=115865 *end=115866.
1755 * text='115867-1..+3' sets *begin=115866 *end=115869.
1756 *
1757 * Supported patterns for text:
1758 * <range>
1759 * <value> - returns *begin=value *end=*begin+1.
1760 * <value1>..<value2> - returns *begin=value1 *end=value2.
1761 * <value>..+<number> - returns *begin=value *end=*begin+number.
1762 * <value>
1763 * <number>
1764 * <number>+<number>
1765 * <number>-<number>
1766 *
1767 * <number>: [0-9]+
1768 *
1769 * If not specified, *end defaults to *begin+1.
1770 *
1771 * Returns 0 on success, else -1, with *string_end pointing to first unused
1772 * character.
1773 */
1774 static int read_number_range(const char *text, int *begin, int *end, char **string_end)
1775 {
1776 int e;
1777 e = read_number_delta(text, begin, string_end);
1778 if (e)
1779 return e;
1780 if (string_end && (*string_end)[0] == '.' && (*string_end)[1] == '.') {
1781 int relative;
1782 e = read_number((*string_end) + 2, end, &relative, string_end);
1783 if (e)
1784 return e;
1785 if (relative)
1786 *end += *begin;
1787 } else {
1788 *end = *begin + 1;
1789 }
1790 if (*end < *begin) {
1791 fprintf(stderr, "Range %i..%i has negative extent, at start of '%s'.\n",
1792 *begin, *end, text);
1793 return -1;
1794 }
1795 if (0) fprintf(stderr, "text='%s': *begin=%i *end=%i\n", text, *begin, *end);
1796
1797 return 0;
1798 }
1799
1800 /* Format: <range>[,<range>]+
1801 *
1802 * For description of <range>, see read_number_range() above.
1803 *
1804 * E.g.:
1805 * MEMENTO_SQUEEZES=1234-2..+4,2345,2350..+2
1806 */
1807 static int Memento_add_squeezes(const char *text)
1808 {
1809 int e = 0;
1810 for(;;) {
1811 int begin;
1812 int end;
1813 char *string_end;
1814 if (!*text)
1815 break;
1816 e = read_number_range(text, &begin, &end, &string_end);
1817 if (e)
1818 break;
1819 if (*string_end && *string_end != ',') {
1820 fprintf(stderr, "Expecting comma at start of '%s'.\n", string_end);
1821 e = -1;
1822 break;
1823 }
1824 fprintf(stderr, "Adding squeeze range %i..%i.\n",
1825 begin, end);
1826 memento.squeezes_num += 1;
1827 memento.squeezes = MEMENTO_UNDERLYING_REALLOC(
1828 memento.squeezes,
1829 memento.squeezes_num * sizeof(*memento.squeezes)
1830 );
1831 if (!memento.squeezes) {
1832 fprintf(stderr, "Failed to allocate memory for memento.squeezes_num=%i\n",
1833 memento.squeezes_num);
1834 e = -1;
1835 break;
1836 }
1837 memento.squeezes[memento.squeezes_num-1].begin = begin;
1838 memento.squeezes[memento.squeezes_num-1].end = end;
1839
1840 if (*string_end == 0)
1841 break;
1842 text = string_end + 1;
1843 }
1844
1845 return e;
1846 }
1847
1848 static void Memento_init(void)
1849 {
1850 char *env;
1851 memset(&memento, 0, sizeof(memento));
1852 memento.inited = 1;
1853 memento.used.head = NULL;
1854 memento.used.tail = NULL;
1855 memento.free.head = NULL;
1856 memento.free.tail = NULL;
1857 memento.sequence = 0;
1858 memento.countdown = 1024;
1859 memento.squeezes = NULL;
1860 memento.squeezes_num = 0;
1861 memento.squeezes_pos = 0;
1862
1863 env = getenv("MEMENTO_FAILAT");
1864 memento.failAt = (env ? atoi(env) : 0);
1865
1866 env = getenv("MEMENTO_BREAKAT");
1867 memento.breakAt = (env ? atoi(env) : 0);
1868
1869 env = getenv("MEMENTO_PARANOIA");
1870 memento.paranoia = (env ? atoi(env) : 0);
1871 if (memento.paranoia == 0)
1872 memento.paranoia = -1024;
1873
1874 env = getenv("MEMENTO_PARANOIDAT");
1875 memento.paranoidAt = (env ? atoi(env) : 0);
1876
1877 env = getenv("MEMENTO_SQUEEZEAT");
1878 memento.squeezeAt = (env ? atoi(env) : 0);
1879
1880 env = getenv("MEMENTO_PATTERN");
1881 memento.pattern = (env ? atoi(env) : 0);
1882
1883 env = getenv("MEMENTO_HIDE_MULTIPLE_REALLOCS");
1884 memento.hideMultipleReallocs = (env ? atoi(env) : 0);
1885
1886 env = getenv("MEMENTO_ABORT_ON_LEAK");
1887 memento.abortOnLeak = (env ? atoi(env) : 0);
1888
1889 env = getenv("MEMENTO_ABORT_ON_CORRUPTION");
1890 memento.abortOnCorruption = (env ? atoi(env) : 0);
1891
1892 env = getenv("MEMENTO_SQUEEZES");
1893 if (env) {
1894 int e;
1895 fprintf(stderr, "Parsing squeeze ranges in MEMENTO_SQUEEZES=%s\n", env);
1896 e = Memento_add_squeezes(env);
1897 if (e) {
1898 fprintf(stderr, "Failed to parse MEMENTO_SQUEEZES=%s\n", env);
1899 exit(1);
1900 }
1901 }
1902
1903 env = getenv("MEMENTO_MAXMEMORY");
1904 memento.maxMemory = (env ? atoi(env) : 0);
1905
1906 atexit(Memento_fin);
1907
1908 Memento_initMutex(&memento.mutex);
1909
1910 Memento_initStacktracer();
1911
1912 Memento_breakpoint();
1913 }
1914
1915 typedef struct findBlkData {
1916 void *addr;
1917 Memento_BlkHeader *blk;
1918 int flags;
1919 } findBlkData;
1920
1921 static int Memento_containsAddr(Memento_BlkHeader *b,
1922 void *arg)
1923 {
1924 findBlkData *data = (findBlkData *)arg;
1925 char *blkend = &((char *)MEMBLK_TOBLK(b))[b->rawsize];
1926 if ((MEMBLK_TOBLK(b) <= data->addr) &&
1927 ((void *)blkend > data->addr)) {
1928 data->blk = b;
1929 data->flags = 1;
1930 return 1;
1931 }
1932 if (((void *)b <= data->addr) &&
1933 (MEMBLK_TOBLK(b) > data->addr)) {
1934 data->blk = b;
1935 data->flags = 2;
1936 return 1;
1937 }
1938 if (((void *)blkend <= data->addr) &&
1939 ((void *)(blkend + Memento_PostSize) > data->addr)) {
1940 data->blk = b;
1941 data->flags = 3;
1942 return 1;
1943 }
1944 return 0;
1945 }
1946
1947 void Memento_info(void *addr)
1948 {
1949 #ifdef MEMENTO_DETAILS
1950 findBlkData data;
1951
1952 MEMENTO_LOCK();
1953 data.addr = addr;
1954 data.blk = NULL;
1955 data.flags = 0;
1956 Memento_appBlocks(&memento.used, Memento_containsAddr, &data);
1957 if (data.blk != NULL)
1958 showInfo(data.blk, NULL);
1959 data.blk = NULL;
1960 data.flags = 0;
1961 Memento_appBlocks(&memento.free, Memento_containsAddr, &data);
1962 if (data.blk != NULL)
1963 showInfo(data.blk, NULL);
1964 MEMENTO_UNLOCK();
1965 #else
1966 printf("Memento not compiled with details support\n");
1967 #endif
1968 }
1969
1970 #ifdef MEMENTO_HAS_FORK
1971 #include <unistd.h>
1972 #include <sys/wait.h>
1973 #include <time.h>
1974 #ifdef MEMENTO_STACKTRACE_METHOD
1975 #if MEMENTO_STACKTRACE_METHOD == 1
1976 #include <signal.h>
1977 #endif
1978 #endif
1979
1980 /* FIXME: Find some portable way of getting this */
1981 /* MacOSX has 10240, Ubuntu seems to have 256 */
1982 #ifndef OPEN_MAX
1983 #define OPEN_MAX 10240
1984 #endif
1985
1986 /* stashed_map[j] = i means that file descriptor i-1 was duplicated to j */
1987 int stashed_map[OPEN_MAX];
1988
1989 static void Memento_signal(int sig)
1990 {
1991 (void)sig;
1992 fprintf(stderr, "SEGV at:\n");
1993 memento.segv = 1;
1994 Memento_bt_internal(0);
1995
1996 exit(1);
1997 }
1998
1999 static int squeeze(void)
2000 {
2001 pid_t pid;
2002 int i, status;
2003
2004 if (memento.patternBit < 0)
2005 return 1;
2006 if (memento.squeezing && memento.patternBit >= MEMENTO_MAXPATTERN)
2007 return 1;
2008
2009 if (memento.patternBit == 0)
2010 memento.squeezeAt = memento.sequence;
2011
2012 if (!memento.squeezing) {
2013 fprintf(stderr, "Memory squeezing @ %d\n", memento.squeezeAt);
2014 } else
2015 fprintf(stderr, "Memory squeezing @ %d (%x,%x)\n", memento.squeezeAt, memento.pattern, memento.patternBit);
2016
2017 /* When we fork below, the child is going to snaffle all our file pointers
2018 * and potentially corrupt them. Let's make copies of all of them before
2019 * we fork, so we can restore them when we restart. */
2020 for (i = 0; i < OPEN_MAX; i++) {
2021 if (stashed_map[i] == 0) {
2022 int j = dup(i);
2023 if (j >= 0) {
2024 stashed_map[j] = i+1;
2025 }
2026 }
2027 }
2028
2029 fprintf(stderr, "Failing at:\n");
2030 Memento_bt_internal(2);
2031 pid = fork();
2032 if (pid == 0) {
2033 /* Child */
2034 signal(SIGSEGV, Memento_signal);
2035 /* Close the dup-licated fds to avoid them getting corrupted by faulty
2036 * code. */
2037 for (i = 0; i < OPEN_MAX; i++) {
2038 if (stashed_map[i] != 0) {
2039 /* We close duplicated fds, just in case child has some bad
2040 * code that modifies/closes random fds. */
2041 close(i);
2042 }
2043 }
2044 /* In the child, we always fail the next allocation. */
2045 if (memento.patternBit == 0) {
2046 memento.patternBit = 1;
2047 } else
2048 memento.patternBit <<= 1;
2049 memento.squeezing = 1;
2050
2051 /* This is necessary to allow Memento_failThisEventLocked() near the
2052 * end to do 'return squeeze();'. */
2053 memento.squeezes_num = 0;
2054
2055 return 1;
2056 }
2057
2058 /* In the parent if we hit another allocation, pass it (and record the
2059 * fact we passed it in the pattern. */
2060 memento.pattern |= memento.patternBit;
2061 memento.patternBit <<= 1;
2062
2063 /* Wait for pid to finish, with a timeout. */
2064 {
2065 struct timespec tm = { 0, 10 * 1000 * 1000 }; /* 10ms = 100th sec */
2066 int timeout = 30 * 1000 * 1000; /* time out in microseconds! */
2067 while (waitpid(pid, &status, WNOHANG) == 0) {
2068 nanosleep(&tm, NULL);
2069 timeout -= (int)(tm.tv_nsec/1000);
2070 tm.tv_nsec *= 2;
2071 if (tm.tv_nsec > 999999999)
2072 tm.tv_nsec = 999999999;
2073 if (timeout <= 0) {
2074 char text[32];
2075 fprintf(stderr, "Child is taking a long time to die. Killing it.\n");
2076 sprintf(text, "kill %d", pid);
2077 system(text);
2078 break;
2079 }
2080 }
2081 }
2082
2083 if (status != 0) {
2084 fprintf(stderr, "Child status=%d\n", status);
2085 }
2086
2087 /* Put the files back */
2088 for (i = 0; i < OPEN_MAX; i++) {
2089 if (stashed_map[i] != 0) {
2090 dup2(i, stashed_map[i]-1);
2091 close(i);
2092 stashed_map[i] = 0;
2093 }
2094 }
2095
2096 return 0;
2097 }
2098 #else
2099 #include <signal.h>
2100
2101 static void Memento_signal(int sig)
2102 {
2103 (void)sig;
2104 memento.segv = 1;
2105 /* If we just return from this function the SEGV will be unhandled, and
2106 * we'll launch into whatever JIT debugging system the OS provides. At
2107 * least fprintf(stderr, something useful first. If MEMENTO_NOJIT is set, then
2108 * just exit to avoid the JIT (and get the usual atexit handling). */
2109 if (getenv("MEMENTO_NOJIT"))
2110 exit(1);
2111 else
2112 Memento_fin();
2113 }
2114
2115 static int squeeze(void)
2116 {
2117 fprintf(stderr, "Memento memory squeezing disabled as no fork!\n");
2118 return 0;
2119 }
2120 #endif
2121
2122 static void Memento_startFailing(void)
2123 {
2124 if (!memento.failing) {
2125 fprintf(stderr, "Starting to fail...\n");
2126 Memento_bt();
2127 fflush(stderr);
2128 memento.failing = 1;
2129 memento.failAt = memento.sequence;
2130 memento.nextFailAt = memento.sequence+1;
2131 memento.pattern = 0;
2132 memento.patternBit = 0;
2133 signal(SIGSEGV, Memento_signal);
2134 signal(SIGABRT, Memento_signal);
2135 Memento_breakpointLocked();
2136 }
2137 }
2138
2139 static int Memento_event(void)
2140 {
2141 memento.sequence++;
2142 if ((memento.sequence >= memento.paranoidAt) && (memento.paranoidAt != 0)) {
2143 memento.paranoia = 1;
2144 memento.countdown = 1;
2145 }
2146 if (--memento.countdown == 0) {
2147 Memento_checkAllMemoryLocked();
2148 if (memento.paranoia > 0)
2149 memento.countdown = memento.paranoia;
2150 else
2151 {
2152 memento.countdown = -memento.paranoia;
2153 if (memento.paranoia > INT_MIN/2)
2154 memento.paranoia *= 2;
2155 }
2156 }
2157
2158 if (memento.sequence == memento.breakAt) {
2159 fprintf(stderr, "Breaking at event %d\n", memento.breakAt);
2160 return 1;
2161 }
2162 return 0;
2163 }
2164
2165 int Memento_sequence(void)
2166 {
2167 return memento.sequence;
2168 }
2169
2170 int Memento_breakAt(int event)
2171 {
2172 MEMENTO_LOCK();
2173 memento.breakAt = event;
2174 MEMENTO_UNLOCK();
2175 return event;
2176 }
2177
2178 static void *safe_find_block(void *ptr)
2179 {
2180 Memento_BlkHeader *block;
2181 int valid;
2182
2183 if (ptr == NULL)
2184 return NULL;
2185
2186 block = MEMBLK_FROMBLK(ptr);
2187 /* Sometimes wrapping allocators can mean Memento_label
2188 * is called with a value within the block, rather than
2189 * at the start of the block. If we detect this, find it
2190 * the slow way. */
2191 VALGRIND_MAKE_MEM_DEFINED(&block->child, sizeof(block->child));
2192 VALGRIND_MAKE_MEM_DEFINED(&block->sibling, sizeof(block->sibling));
2193 valid = (block->child == MEMENTO_CHILD_MAGIC &&
2194 block->sibling == MEMENTO_SIBLING_MAGIC);
2195 VALGRIND_MAKE_MEM_NOACCESS(&block->child, sizeof(block->child));
2196 VALGRIND_MAKE_MEM_NOACCESS(&block->sibling, sizeof(block->sibling));
2197 if (!valid)
2198 {
2199 findBlkData data;
2200
2201 data.addr = ptr;
2202 data.blk = NULL;
2203 data.flags = 0;
2204 Memento_appBlocks(&memento.used, Memento_containsAddr, &data);
2205 if (data.blk == NULL)
2206 return NULL;
2207 block = data.blk;
2208 }
2209 return block;
2210 }
2211
2212 void *Memento_label(void *ptr, const char *label)
2213 {
2214 Memento_BlkHeader *block;
2215
2216 if (ptr == NULL)
2217 return NULL;
2218 MEMENTO_LOCK();
2219 block = safe_find_block(ptr);
2220 if (block != NULL)
2221 {
2222 VALGRIND_MAKE_MEM_DEFINED(&block->label, sizeof(block->label));
2223 block->label = label;
2224 VALGRIND_MAKE_MEM_NOACCESS(&block->label, sizeof(block->label));
2225 }
2226 MEMENTO_UNLOCK();
2227 return ptr;
2228 }
2229
2230 void Memento_tick(void)
2231 {
2232 MEMENTO_LOCK();
2233 if (Memento_event()) Memento_breakpointLocked();
2234 MEMENTO_UNLOCK();
2235 }
2236
2237 static int Memento_failThisEventLocked(void)
2238 {
2239 int failThisOne;
2240
2241 if (Memento_event()) Memento_breakpointLocked();
2242
2243 if (!memento.squeezing && memento.squeezes_num) {
2244 /* Move to next relevant squeeze region if appropriate. */
2245 for ( ; memento.squeezes_pos != memento.squeezes_num; memento.squeezes_pos++) {
2246 if (memento.sequence < memento.squeezes[memento.squeezes_pos].end)
2247 break;
2248 }
2249
2250 /* See whether memento.sequence is within this squeeze region. */
2251 if (memento.squeezes_pos < memento.squeezes_num) {
2252 int begin = memento.squeezes[memento.squeezes_pos].begin;
2253 int end = memento.squeezes[memento.squeezes_pos].end;
2254 if (memento.sequence >= begin && memento.sequence < end) {
2255 if (1) {
2256 fprintf(stderr,
2257 "squeezes match memento.sequence=%i: memento.squeezes_pos=%i/%i %i..%i\n",
2258 memento.sequence,
2259 memento.squeezes_pos,
2260 memento.squeezes_num,
2261 memento.squeezes[memento.squeezes_pos].begin,
2262 memento.squeezes[memento.squeezes_pos].end
2263 );
2264 }
2265 return squeeze();
2266 }
2267 }
2268 }
2269
2270 if ((memento.sequence >= memento.failAt) && (memento.failAt != 0))
2271 Memento_startFailing();
2272 if ((memento.squeezes_num==0) && (memento.sequence >= memento.squeezeAt) && (memento.squeezeAt != 0))
2273 return squeeze();
2274
2275 if (!memento.failing)
2276 return 0;
2277 failThisOne = ((memento.patternBit & memento.pattern) == 0);
2278 /* If we are failing, and we've reached the end of the pattern and we've
2279 * still got bits available in the pattern word, and we haven't already
2280 * set a nextPattern, then extend the pattern. */
2281 if (memento.failing &&
2282 ((~(memento.patternBit-1) & memento.pattern) == 0) &&
2283 (memento.patternBit != 0) &&
2284 memento.nextPattern == 0)
2285 {
2286 /* We'll fail this one, and set the 'next' one to pass it. */
2287 memento.nextFailAt = memento.failAt;
2288 memento.nextPattern = memento.pattern | memento.patternBit;
2289 }
2290 memento.patternBit = (memento.patternBit ? memento.patternBit << 1 : 1);
2291
2292 return failThisOne;
2293 }
2294
2295 int Memento_failThisEvent(void)
2296 {
2297 int ret;
2298
2299 if (!memento.inited)
2300 Memento_init();
2301
2302 MEMENTO_LOCK();
2303 ret = Memento_failThisEventLocked();
2304 MEMENTO_UNLOCK();
2305 return ret;
2306 }
2307
2308 static void *do_malloc(size_t s, int eventType)
2309 {
2310 Memento_BlkHeader *memblk;
2311 size_t smem = MEMBLK_SIZE(s);
2312
2313 (void)eventType;
2314
2315 if (Memento_failThisEventLocked()) {
2316 errno = ENOMEM;
2317 return NULL;
2318 }
2319
2320 if (s == 0)
2321 return NULL;
2322
2323 memento.numMallocs++;
2324
2325 if (memento.maxMemory != 0 && memento.alloc + s > memento.maxMemory) {
2326 errno = ENOMEM;
2327 return NULL;
2328 }
2329
2330 memblk = MEMENTO_UNDERLYING_MALLOC(smem);
2331 if (memblk == NULL)
2332 return NULL;
2333
2334 memento.alloc += s;
2335 memento.totalAlloc += s;
2336 if (memento.peakAlloc < memento.alloc)
2337 memento.peakAlloc = memento.alloc;
2338 #ifndef MEMENTO_LEAKONLY
2339 memset(MEMBLK_TOBLK(memblk), MEMENTO_ALLOCFILL, s);
2340 #endif
2341 memblk->rawsize = s;
2342 memblk->sequence = memento.sequence;
2343 memblk->lastCheckedOK = memblk->sequence;
2344 memblk->flags = 0;
2345 memblk->label = 0;
2346 memblk->child = MEMENTO_CHILD_MAGIC;
2347 memblk->sibling = MEMENTO_SIBLING_MAGIC;
2348 #ifdef MEMENTO_DETAILS
2349 memblk->details = NULL;
2350 memblk->details_tail = &memblk->details;
2351 Memento_storeDetails(memblk, eventType);
2352 #endif /* MEMENTO_DETAILS */
2353 Memento_addBlockHead(&memento.used, memblk, 0);
2354
2355 if (memento.leaking > 0)
2356 memblk->flags |= Memento_Flag_KnownLeak;
2357
2358 return MEMBLK_TOBLK(memblk);
2359 }
2360
2361 char *Memento_strdup(const char *text)
2362 {
2363 size_t len = strlen(text) + 1;
2364 char *ret;
2365
2366 if (!memento.inited)
2367 Memento_init();
2368
2369 MEMENTO_LOCK();
2370 ret = do_malloc(len, Memento_EventType_strdup);
2371 MEMENTO_UNLOCK();
2372
2373 if (ret != NULL)
2374 memcpy(ret, text, len);
2375
2376 return ret;
2377 }
2378
2379 int Memento_asprintf(char **ret, const char *format, ...)
2380 {
2381 va_list va;
2382 int n;
2383 int n2;
2384
2385 if (!memento.inited)
2386 Memento_init();
2387
2388 va_start(va, format);
2389 n = vsnprintf(NULL, 0, format, va);
2390 va_end(va);
2391 if (n < 0)
2392 return n;
2393
2394 MEMENTO_LOCK();
2395 *ret = do_malloc(n+1, Memento_EventType_asprintf);
2396 MEMENTO_UNLOCK();
2397 if (*ret == NULL)
2398 return -1;
2399
2400 va_start(va, format);
2401 n2 = vsnprintf(*ret, n + 1, format, va);
2402 va_end(va);
2403
2404 return n2;
2405 }
2406
2407 int Memento_vasprintf(char **ret, const char *format, va_list ap)
2408 {
2409 int n;
2410 va_list ap2;
2411 va_copy(ap2, ap);
2412
2413 if (!memento.inited)
2414 Memento_init();
2415
2416 n = vsnprintf(NULL, 0, format, ap);
2417 if (n < 0) {
2418 va_end(ap2);
2419 return n;
2420 }
2421
2422 MEMENTO_LOCK();
2423 *ret = do_malloc(n+1, Memento_EventType_vasprintf);
2424 MEMENTO_UNLOCK();
2425 if (*ret == NULL) {
2426 va_end(ap2);
2427 return -1;
2428 }
2429
2430 n = vsnprintf(*ret, n + 1, format, ap2);
2431 va_end(ap2);
2432
2433 return n;
2434 }
2435
2436 void *Memento_malloc(size_t s)
2437 {
2438 void *ret;
2439
2440 if (!memento.inited)
2441 Memento_init();
2442
2443 MEMENTO_LOCK();
2444 ret = do_malloc(s, Memento_EventType_malloc);
2445 MEMENTO_UNLOCK();
2446
2447 return ret;
2448 }
2449
2450 void *Memento_calloc(size_t n, size_t s)
2451 {
2452 void *block;
2453
2454 if (!memento.inited)
2455 Memento_init();
2456
2457 MEMENTO_LOCK();
2458 block = do_malloc(n*s, Memento_EventType_calloc);
2459 MEMENTO_UNLOCK();
2460 if (block)
2461 memset(block, 0, n*s);
2462
2463 return block;
2464 }
2465
2466 static void do_reference(Memento_BlkHeader *blk, int event)
2467 {
2468 #ifdef MEMENTO_DETAILS
2469 Memento_storeDetails(blk, event);
2470 #endif /* MEMENTO_DETAILS */
2471 }
2472
2473 int Memento_checkPointerOrNull(void *blk)
2474 {
2475 if (blk == NULL)
2476 return 0;
2477 if (blk == MEMENTO_PREFILL_PTR)
2478 fprintf(stderr, "Prefill value found as pointer - buffer underrun?\n");
2479 else if (blk == MEMENTO_POSTFILL_PTR)
2480 fprintf(stderr, "Postfill value found as pointer - buffer overrun?\n");
2481 else if (blk == MEMENTO_ALLOCFILL_PTR)
2482 fprintf(stderr, "Allocfill value found as pointer - use of uninitialised value?\n");
2483 else if (blk == MEMENTO_FREEFILL_PTR)
2484 fprintf(stderr, "Allocfill value found as pointer - use after free?\n");
2485 else
2486 return 0;
2487 #ifdef MEMENTO_DETAILS
2488 fprintf(stderr, "Current backtrace:\n");
2489 Memento_bt();
2490 fprintf(stderr, "History:\n");
2491 Memento_info(blk);
2492 #endif
2493 return 1;
2494 }
2495
2496 int Memento_checkBytePointerOrNull(void *blk)
2497 {
2498 unsigned char i;
2499 if (blk == NULL)
2500 return 0;
2501 Memento_checkPointerOrNull(blk);
2502
2503 i = *(unsigned char *)blk;
2504
2505 if (i == MEMENTO_PREFILL_UBYTE)
2506 fprintf(stderr, "Prefill value found - buffer underrun?\n");
2507 else if (i == MEMENTO_POSTFILL_UBYTE)
2508 fprintf(stderr, "Postfill value found - buffer overrun?\n");
2509 else if (i == MEMENTO_ALLOCFILL_UBYTE)
2510 fprintf(stderr, "Allocfill value found - use of uninitialised value?\n");
2511 else if (i == MEMENTO_FREEFILL_UBYTE)
2512 fprintf(stderr, "Allocfill value found - use after free?\n");
2513 else
2514 return 0;
2515 #ifdef MEMENTO_DETAILS
2516 fprintf(stderr, "Current backtrace:\n");
2517 Memento_bt();
2518 fprintf(stderr, "History:\n");
2519 Memento_info(blk);
2520 #endif
2521 Memento_breakpoint();
2522 return 1;
2523 }
2524
2525 int Memento_checkShortPointerOrNull(void *blk)
2526 {
2527 unsigned short i;
2528 if (blk == NULL)
2529 return 0;
2530 Memento_checkPointerOrNull(blk);
2531
2532 i = *(unsigned short *)blk;
2533
2534 if (i == MEMENTO_PREFILL_USHORT)
2535 fprintf(stderr, "Prefill value found - buffer underrun?\n");
2536 else if (i == MEMENTO_POSTFILL_USHORT)
2537 fprintf(stderr, "Postfill value found - buffer overrun?\n");
2538 else if (i == MEMENTO_ALLOCFILL_USHORT)
2539 fprintf(stderr, "Allocfill value found - use of uninitialised value?\n");
2540 else if (i == MEMENTO_FREEFILL_USHORT)
2541 fprintf(stderr, "Allocfill value found - use after free?\n");
2542 else
2543 return 0;
2544 #ifdef MEMENTO_DETAILS
2545 fprintf(stderr, "Current backtrace:\n");
2546 Memento_bt();
2547 fprintf(stderr, "History:\n");
2548 Memento_info(blk);
2549 #endif
2550 Memento_breakpoint();
2551 return 1;
2552 }
2553
2554 int Memento_checkIntPointerOrNull(void *blk)
2555 {
2556 unsigned int i;
2557 if (blk == NULL)
2558 return 0;
2559 Memento_checkPointerOrNull(blk);
2560
2561 i = *(unsigned int *)blk;
2562
2563 if (i == MEMENTO_PREFILL_UINT)
2564 fprintf(stderr, "Prefill value found - buffer underrun?\n");
2565 else if (i == MEMENTO_POSTFILL_UINT)
2566 fprintf(stderr, "Postfill value found - buffer overrun?\n");
2567 else if (i == MEMENTO_ALLOCFILL_UINT)
2568 fprintf(stderr, "Allocfill value found - use of uninitialised value?\n");
2569 else if (i == MEMENTO_FREEFILL_UINT)
2570 fprintf(stderr, "Allocfill value found - use after free?\n");
2571 else
2572 return 0;
2573 #ifdef MEMENTO_DETAILS
2574 fprintf(stderr, "Current backtrace:\n");
2575 Memento_bt();
2576 fprintf(stderr, "History:\n");
2577 Memento_info(blk);
2578 #endif
2579 Memento_breakpoint();
2580 return 1;
2581 }
2582
2583 static void *do_takeRef(void *blk)
2584 {
2585 MEMENTO_LOCK();
2586 do_reference(safe_find_block(blk), Memento_EventType_takeRef);
2587 MEMENTO_UNLOCK();
2588 return blk;
2589 }
2590
2591 void *Memento_takeByteRef(void *blk)
2592 {
2593 if (!memento.inited)
2594 Memento_init();
2595
2596 if (Memento_event()) Memento_breakpoint();
2597
2598 if (!blk)
2599 return NULL;
2600
2601 (void)Memento_checkBytePointerOrNull(blk);
2602
2603 return do_takeRef(blk);
2604 }
2605
2606 void *Memento_takeShortRef(void *blk)
2607 {
2608 if (!memento.inited)
2609 Memento_init();
2610
2611 if (Memento_event()) Memento_breakpoint();
2612
2613 if (!blk)
2614 return NULL;
2615
2616 (void)Memento_checkShortPointerOrNull(blk);
2617
2618 return do_takeRef(blk);
2619 }
2620
2621 void *Memento_takeIntRef(void *blk)
2622 {
2623 if (!memento.inited)
2624 Memento_init();
2625
2626 if (Memento_event()) Memento_breakpoint();
2627
2628 if (!blk)
2629 return NULL;
2630
2631 (void)Memento_checkIntPointerOrNull(blk);
2632
2633 return do_takeRef(blk);
2634 }
2635
2636 void *Memento_takeRef(void *blk)
2637 {
2638 if (!memento.inited)
2639 Memento_init();
2640
2641 if (Memento_event()) Memento_breakpoint();
2642
2643 if (!blk)
2644 return NULL;
2645
2646 return do_takeRef(blk);
2647 }
2648
2649 static void *do_dropRef(void *blk)
2650 {
2651 MEMENTO_LOCK();
2652 do_reference(safe_find_block(blk), Memento_EventType_dropRef);
2653 MEMENTO_UNLOCK();
2654 return blk;
2655 }
2656
2657 void *Memento_dropByteRef(void *blk)
2658 {
2659 if (!memento.inited)
2660 Memento_init();
2661
2662 if (Memento_event()) Memento_breakpoint();
2663
2664 if (!blk)
2665 return NULL;
2666
2667 Memento_checkBytePointerOrNull(blk);
2668
2669 return do_dropRef(blk);
2670 }
2671
2672 void *Memento_dropShortRef(void *blk)
2673 {
2674 if (!memento.inited)
2675 Memento_init();
2676
2677 if (Memento_event()) Memento_breakpoint();
2678
2679 if (!blk)
2680 return NULL;
2681
2682 Memento_checkShortPointerOrNull(blk);
2683
2684 return do_dropRef(blk);
2685 }
2686
2687 void *Memento_dropIntRef(void *blk)
2688 {
2689 if (!memento.inited)
2690 Memento_init();
2691
2692 if (Memento_event()) Memento_breakpoint();
2693
2694 if (!blk)
2695 return NULL;
2696
2697 Memento_checkIntPointerOrNull(blk);
2698
2699 return do_dropRef(blk);
2700 }
2701
2702 void *Memento_dropRef(void *blk)
2703 {
2704 if (!memento.inited)
2705 Memento_init();
2706
2707 if (Memento_event()) Memento_breakpoint();
2708
2709 if (!blk)
2710 return NULL;
2711
2712 return do_dropRef(blk);
2713 }
2714
2715 void *Memento_adjustRef(void *blk, int adjust)
2716 {
2717 if (Memento_event()) Memento_breakpoint();
2718
2719 if (blk == NULL)
2720 return NULL;
2721
2722 while (adjust > 0)
2723 {
2724 do_takeRef(blk);
2725 adjust--;
2726 }
2727 while (adjust < 0)
2728 {
2729 do_dropRef(blk);
2730 adjust++;
2731 }
2732
2733 return blk;
2734 }
2735
2736 void *Memento_reference(void *blk)
2737 {
2738 if (!blk)
2739 return NULL;
2740
2741 if (!memento.inited)
2742 Memento_init();
2743
2744 MEMENTO_LOCK();
2745 do_reference(safe_find_block(blk), Memento_EventType_reference);
2746 MEMENTO_UNLOCK();
2747 return blk;
2748 }
2749
2750 /* Treat blocks from the user with suspicion, and check them the slow
2751 * but safe way. */
2752 static int checkBlockUser(Memento_BlkHeader *memblk, const char *action)
2753 {
2754 #ifndef MEMENTO_LEAKONLY
2755 BlkCheckData data;
2756
2757 memset(&data, 0, sizeof(data));
2758 Memento_appBlockUser(&memento.used, Memento_Internal_checkAllocedBlock,
2759 &data, memblk);
2760 if (!data.found) {
2761 /* Failure! */
2762 fprintf(stderr, "Attempt to %s block ", action);
2763 showBlock(memblk, 32);
2764 fprintf(stderr, "\n");
2765 Memento_breakpointLocked();
2766 return 1;
2767 } else if (data.preCorrupt || data.postCorrupt) {
2768 fprintf(stderr, "Block ");
2769 showBlock(memblk, ' ');
2770 fprintf(stderr, " found to be corrupted on %s!\n", action);
2771 if (data.preCorrupt) {
2772 fprintf(stderr, "Preguard corrupted\n");
2773 }
2774 if (data.postCorrupt) {
2775 fprintf(stderr, "Postguard corrupted\n");
2776 }
2777 fprintf(stderr, "Block last checked OK at allocation %d. Now %d.\n",
2778 memblk->lastCheckedOK, memento.sequence);
2779 if ((memblk->flags & Memento_Flag_Reported) == 0)
2780 {
2781 memblk->flags |= Memento_Flag_Reported;
2782 Memento_breakpointLocked();
2783 }
2784 return 1;
2785 }
2786 #endif
2787 return 0;
2788 }
2789
2790 static int checkBlock(Memento_BlkHeader *memblk, const char *action)
2791 {
2792 #ifndef MEMENTO_LEAKONLY
2793 BlkCheckData data;
2794 #endif
2795
2796 if (memblk->child != MEMENTO_CHILD_MAGIC ||
2797 memblk->sibling != MEMENTO_SIBLING_MAGIC)
2798 {
2799 /* Failure! */
2800 fprintf(stderr, "Attempt to %s invalid block ", action);
2801 showBlock(memblk, 32);
2802 fprintf(stderr, "\n");
2803 Memento_breakpointLocked();
2804 return 1;
2805 }
2806
2807 #ifndef MEMENTO_LEAKONLY
2808 memset(&data, 0, sizeof(data));
2809 Memento_appBlock(&memento.used, Memento_Internal_checkAllocedBlock,
2810 &data, memblk);
2811 if (!data.found) {
2812 /* Failure! */
2813 fprintf(stderr, "Attempt to %s block ", action);
2814 showBlock(memblk, 32);
2815 fprintf(stderr, "\n");
2816 Memento_breakpointLocked();
2817 return 1;
2818 } else if (data.preCorrupt || data.postCorrupt) {
2819 fprintf(stderr, "Block ");
2820 showBlock(memblk, ' ');
2821 fprintf(stderr, " found to be corrupted on %s!\n", action);
2822 if (data.preCorrupt) {
2823 fprintf(stderr, "Preguard corrupted\n");
2824 }
2825 if (data.postCorrupt) {
2826 fprintf(stderr, "Postguard corrupted\n");
2827 }
2828 fprintf(stderr, "Block last checked OK at allocation %d. Now %d.\n",
2829 memblk->lastCheckedOK, memento.sequence);
2830 if ((memblk->flags & Memento_Flag_Reported) == 0)
2831 {
2832 memblk->flags |= Memento_Flag_Reported;
2833 Memento_breakpointLocked();
2834 }
2835 return 1;
2836 }
2837 #endif
2838 return 0;
2839 }
2840
2841 static void do_free(void *blk, int eventType)
2842 {
2843 Memento_BlkHeader *memblk;
2844
2845 (void)eventType;
2846
2847 if (Memento_event()) Memento_breakpointLocked();
2848
2849 if (blk == NULL)
2850 return;
2851
2852 memblk = MEMBLK_FROMBLK(blk);
2853 VALGRIND_MAKE_MEM_DEFINED(memblk, sizeof(*memblk));
2854 if (checkBlock(memblk, "free"))
2855 {
2856 if (memento.abortOnCorruption) {
2857 fprintf(stderr, "*** memblk corrupted, calling abort()\n");
2858 abort();
2859 }
2860 return;
2861 }
2862
2863 #ifdef MEMENTO_DETAILS
2864 Memento_storeDetails(memblk, eventType);
2865 #endif
2866
2867 VALGRIND_MAKE_MEM_DEFINED(memblk, sizeof(*memblk));
2868 if (memblk->flags & Memento_Flag_BreakOnFree)
2869 Memento_breakpointLocked();
2870
2871 memento.alloc -= memblk->rawsize;
2872 memento.numFrees++;
2873
2874 Memento_removeBlock(&memento.used, memblk);
2875
2876 VALGRIND_MAKE_MEM_DEFINED(memblk, sizeof(*memblk));
2877 if (Memento_Internal_makeSpace(MEMBLK_SIZE(memblk->rawsize))) {
2878 VALGRIND_MAKE_MEM_DEFINED(memblk, sizeof(*memblk));
2879 VALGRIND_MAKE_MEM_DEFINED(MEMBLK_TOBLK(memblk),
2880 memblk->rawsize + Memento_PostSize);
2881 #ifndef MEMENTO_LEAKONLY
2882 memset(MEMBLK_TOBLK(memblk), MEMENTO_FREEFILL, memblk->rawsize);
2883 #endif
2884 memblk->flags |= Memento_Flag_Freed;
2885 Memento_addBlockTail(&memento.free, memblk, 1);
2886 } else {
2887 free_block(memblk);
2888 }
2889 }
2890
2891 void Memento_free(void *blk)
2892 {
2893 if (!memento.inited)
2894 Memento_init();
2895
2896 MEMENTO_LOCK();
2897 do_free(blk, Memento_EventType_free);
2898 MEMENTO_UNLOCK();
2899 }
2900
2901 static void *do_realloc(void *blk, size_t newsize, int type)
2902 {
2903 Memento_BlkHeader *memblk, *newmemblk;
2904 size_t newsizemem;
2905 int flags;
2906
2907 if (Memento_failThisEventLocked()) {
2908 errno = ENOMEM;
2909 return NULL;
2910 }
2911
2912 memblk = MEMBLK_FROMBLK(blk);
2913 VALGRIND_MAKE_MEM_DEFINED(memblk, sizeof(*memblk));
2914 if (checkBlock(memblk, "realloc")) {
2915 errno = ENOMEM;
2916 return NULL;
2917 }
2918
2919 #ifdef MEMENTO_DETAILS
2920 Memento_storeDetails(memblk, type);
2921 #endif
2922
2923 VALGRIND_MAKE_MEM_DEFINED(memblk, sizeof(*memblk));
2924 if (memblk->flags & Memento_Flag_BreakOnRealloc)
2925 Memento_breakpointLocked();
2926
2927 VALGRIND_MAKE_MEM_DEFINED(memblk, sizeof(*memblk));
2928 if (memento.maxMemory != 0 && memento.alloc - memblk->rawsize + newsize > memento.maxMemory) {
2929 errno = ENOMEM;
2930 return NULL;
2931 }
2932
2933 newsizemem = MEMBLK_SIZE(newsize);
2934 Memento_removeBlock(&memento.used, memblk);
2935 VALGRIND_MAKE_MEM_DEFINED(memblk, sizeof(*memblk));
2936 flags = memblk->flags;
2937 newmemblk = MEMENTO_UNDERLYING_REALLOC(memblk, newsizemem);
2938 if (newmemblk == NULL)
2939 {
2940 Memento_addBlockHead(&memento.used, memblk, 2);
2941 return NULL;
2942 }
2943 memento.numReallocs++;
2944 memento.totalAlloc += newsize;
2945 memento.alloc -= newmemblk->rawsize;
2946 memento.alloc += newsize;
2947 if (memento.peakAlloc < memento.alloc)
2948 memento.peakAlloc = memento.alloc;
2949 newmemblk->flags = flags;
2950 #ifndef MEMENTO_LEAKONLY
2951 if (newmemblk->rawsize < newsize) {
2952 char *newbytes = ((char *)MEMBLK_TOBLK(newmemblk))+newmemblk->rawsize;
2953 VALGRIND_MAKE_MEM_DEFINED(newbytes, newsize - newmemblk->rawsize);
2954 memset(newbytes, MEMENTO_ALLOCFILL, newsize - newmemblk->rawsize);
2955 VALGRIND_MAKE_MEM_UNDEFINED(newbytes, newsize - newmemblk->rawsize);
2956 }
2957 #endif
2958 newmemblk->rawsize = newsize;
2959 #ifndef MEMENTO_LEAKONLY
2960 VALGRIND_MAKE_MEM_DEFINED(newmemblk->preblk, Memento_PreSize);
2961 memset(newmemblk->preblk, MEMENTO_PREFILL, Memento_PreSize);
2962 VALGRIND_MAKE_MEM_UNDEFINED(newmemblk->preblk, Memento_PreSize);
2963 VALGRIND_MAKE_MEM_DEFINED(MEMBLK_POSTPTR(newmemblk), Memento_PostSize);
2964 memset(MEMBLK_POSTPTR(newmemblk), MEMENTO_POSTFILL, Memento_PostSize);
2965 VALGRIND_MAKE_MEM_UNDEFINED(MEMBLK_POSTPTR(newmemblk), Memento_PostSize);
2966 #endif
2967 Memento_addBlockHead(&memento.used, newmemblk, 2);
2968 return MEMBLK_TOBLK(newmemblk);
2969 }
2970
2971 void *Memento_realloc(void *blk, size_t newsize)
2972 {
2973 void *ret;
2974
2975 if (!memento.inited)
2976 Memento_init();
2977
2978 if (blk == NULL)
2979 {
2980 MEMENTO_LOCK();
2981 ret = do_malloc(newsize, Memento_EventType_realloc);
2982 MEMENTO_UNLOCK();
2983 if (!ret) errno = ENOMEM;
2984 return ret;
2985 }
2986 if (newsize == 0) {
2987 MEMENTO_LOCK();
2988 do_free(blk, Memento_EventType_realloc);
2989 MEMENTO_UNLOCK();
2990 return NULL;
2991 }
2992
2993 MEMENTO_LOCK();
2994 ret = do_realloc(blk, newsize, Memento_EventType_realloc);
2995 MEMENTO_UNLOCK();
2996 if (!ret) errno = ENOMEM;
2997 return ret;
2998 }
2999
3000 int Memento_checkBlock(void *blk)
3001 {
3002 Memento_BlkHeader *memblk;
3003 int ret;
3004
3005 if (blk == NULL)
3006 return 0;
3007
3008 MEMENTO_LOCK();
3009 memblk = MEMBLK_FROMBLK(blk);
3010 ret = checkBlockUser(memblk, "check");
3011 MEMENTO_UNLOCK();
3012 return ret;
3013 }
3014
3015 #ifndef MEMENTO_LEAKONLY
3016 static int Memento_Internal_checkAllAlloced(Memento_BlkHeader *memblk, void *arg)
3017 {
3018 BlkCheckData *data = (BlkCheckData *)arg;
3019
3020 Memento_Internal_checkAllocedBlock(memblk, data);
3021 if (data->preCorrupt || data->postCorrupt) {
3022 if ((data->found & 2) == 0) {
3023 fprintf(stderr, "Allocated blocks:\n");
3024 data->found |= 2;
3025 }
3026 fprintf(stderr, " Block ");
3027 showBlock(memblk, ' ');
3028 if (data->preCorrupt) {
3029 fprintf(stderr, " Preguard ");
3030 }
3031 if (data->postCorrupt) {
3032 fprintf(stderr, "%s Postguard ",
3033 (data->preCorrupt ? "&" : ""));
3034 }
3035 fprintf(stderr, "corrupted.\n "
3036 "Block last checked OK at allocation %d. Now %d.\n",
3037 memblk->lastCheckedOK, memento.sequence);
3038 data->preCorrupt = 0;
3039 data->postCorrupt = 0;
3040 data->freeCorrupt = 0;
3041 if ((memblk->flags & Memento_Flag_Reported) == 0)
3042 {
3043 memblk->flags |= Memento_Flag_Reported;
3044 Memento_breakpointLocked();
3045 }
3046 }
3047 else
3048 memblk->lastCheckedOK = memento.sequence;
3049 return 0;
3050 }
3051
3052 static int Memento_Internal_checkAllFreed(Memento_BlkHeader *memblk, void *arg)
3053 {
3054 BlkCheckData *data = (BlkCheckData *)arg;
3055
3056 Memento_Internal_checkFreedBlock(memblk, data);
3057 if (data->preCorrupt || data->postCorrupt || data->freeCorrupt) {
3058 if ((data->found & 4) == 0) {
3059 fprintf(stderr, "Freed blocks:\n");
3060 data->found |= 4;
3061 }
3062 fprintf(stderr, " ");
3063 showBlock(memblk, ' ');
3064 if (data->freeCorrupt) {
3065 fprintf(stderr, " index %d (address "FMTP") onwards", (int)data->index,
3066 &((char *)MEMBLK_TOBLK(memblk))[data->index]);
3067 if (data->preCorrupt) {
3068 fprintf(stderr, "+ preguard");
3069 }
3070 if (data->postCorrupt) {
3071 fprintf(stderr, "+ postguard");
3072 }
3073 } else {
3074 if (data->preCorrupt) {
3075 fprintf(stderr, " preguard");
3076 }
3077 if (data->postCorrupt) {
3078 fprintf(stderr, "%s Postguard",
3079 (data->preCorrupt ? "+" : ""));
3080 }
3081 }
3082 VALGRIND_MAKE_MEM_DEFINED(memblk, sizeof(Memento_BlkHeader));
3083 fprintf(stderr, " corrupted.\n"
3084 " Block last checked OK at allocation %d. Now %d.\n",
3085 memblk->lastCheckedOK, memento.sequence);
3086 if ((memblk->flags & Memento_Flag_Reported) == 0)
3087 {
3088 memblk->flags |= Memento_Flag_Reported;
3089 Memento_breakpointLocked();
3090 }
3091 VALGRIND_MAKE_MEM_NOACCESS(memblk, sizeof(Memento_BlkHeader));
3092 data->preCorrupt = 0;
3093 data->postCorrupt = 0;
3094 data->freeCorrupt = 0;
3095 }
3096 else
3097 memblk->lastCheckedOK = memento.sequence;
3098 return 0;
3099 }
3100 #endif /* MEMENTO_LEAKONLY */
3101
3102 static int Memento_checkAllMemoryLocked(void)
3103 {
3104 #ifndef MEMENTO_LEAKONLY
3105 BlkCheckData data;
3106
3107 memset(&data, 0, sizeof(data));
3108 Memento_appBlocks(&memento.used, Memento_Internal_checkAllAlloced, &data);
3109 Memento_appBlocks(&memento.free, Memento_Internal_checkAllFreed, &data);
3110 return data.found;
3111 #else
3112 return 0;
3113 #endif
3114 }
3115
3116 int Memento_checkAllMemory(void)
3117 {
3118 #ifndef MEMENTO_LEAKONLY
3119 int ret;
3120
3121 MEMENTO_LOCK();
3122 ret = Memento_checkAllMemoryLocked();
3123 MEMENTO_UNLOCK();
3124 if (ret & 6) {
3125 Memento_breakpoint();
3126 return 1;
3127 }
3128 return 0;
3129 #endif
3130 }
3131
3132 int Memento_setParanoia(int i)
3133 {
3134 memento.paranoia = i;
3135 if (memento.paranoia > 0)
3136 memento.countdown = memento.paranoia;
3137 else
3138 memento.countdown = -memento.paranoia;
3139 return i;
3140 }
3141
3142 int Memento_paranoidAt(int i)
3143 {
3144 memento.paranoidAt = i;
3145 return i;
3146 }
3147
3148 int Memento_getBlockNum(void *b)
3149 {
3150 Memento_BlkHeader *memblk;
3151 if (b == NULL)
3152 return 0;
3153 memblk = MEMBLK_FROMBLK(b);
3154 return (memblk->sequence);
3155 }
3156
3157 int Memento_check(void)
3158 {
3159 int result;
3160
3161 fprintf(stderr, "Checking memory\n");
3162 result = Memento_checkAllMemory();
3163 fprintf(stderr, "Memory checked!\n");
3164 return result;
3165 }
3166
3167 int Memento_find(void *a)
3168 {
3169 findBlkData data;
3170 int s;
3171
3172 MEMENTO_LOCK();
3173 data.addr = a;
3174 data.blk = NULL;
3175 data.flags = 0;
3176 Memento_appBlocks(&memento.used, Memento_containsAddr, &data);
3177 if (data.blk != NULL) {
3178 fprintf(stderr, "Address "FMTP" is in %sallocated block ",
3179 data.addr,
3180 (data.flags == 1 ? "" : (data.flags == 2 ?
3181 "preguard of " : "postguard of ")));
3182 s = showBlock(data.blk, ' ');
3183 fprintf(stderr, "\n");
3184 MEMENTO_UNLOCK();
3185 return s;
3186 }
3187 data.blk = NULL;
3188 data.flags = 0;
3189 Memento_appBlocks(&memento.free, Memento_containsAddr, &data);
3190 if (data.blk != NULL) {
3191 fprintf(stderr, "Address "FMTP" is in %sfreed block ",
3192 data.addr,
3193 (data.flags == 1 ? "" : (data.flags == 2 ?
3194 "preguard of " : "postguard of ")));
3195 s = showBlock(data.blk, ' ');
3196 fprintf(stderr, "\n");
3197 MEMENTO_UNLOCK();
3198 return s;
3199 }
3200 MEMENTO_UNLOCK();
3201 return 0;
3202 }
3203
3204 void Memento_breakOnFree(void *a)
3205 {
3206 findBlkData data;
3207
3208 MEMENTO_LOCK();
3209 data.addr = a;
3210 data.blk = NULL;
3211 data.flags = 0;
3212 Memento_appBlocks(&memento.used, Memento_containsAddr, &data);
3213 if (data.blk != NULL) {
3214 fprintf(stderr, "Will stop when address "FMTP" (in %sallocated block ",
3215 data.addr,
3216 (data.flags == 1 ? "" : (data.flags == 2 ?
3217 "preguard of " : "postguard of ")));
3218 showBlock(data.blk, ' ');
3219 fprintf(stderr, ") is freed\n");
3220 VALGRIND_MAKE_MEM_DEFINED(data.blk, sizeof(Memento_BlkHeader));
3221 data.blk->flags |= Memento_Flag_BreakOnFree;
3222 VALGRIND_MAKE_MEM_NOACCESS(data.blk, sizeof(Memento_BlkHeader));
3223 MEMENTO_UNLOCK();
3224 return;
3225 }
3226 data.blk = NULL;
3227 data.flags = 0;
3228 Memento_appBlocks(&memento.free, Memento_containsAddr, &data);
3229 if (data.blk != NULL) {
3230 fprintf(stderr, "Can't stop on free; address "FMTP" is in %sfreed block ",
3231 data.addr,
3232 (data.flags == 1 ? "" : (data.flags == 2 ?
3233 "preguard of " : "postguard of ")));
3234 showBlock(data.blk, ' ');
3235 fprintf(stderr, "\n");
3236 MEMENTO_UNLOCK();
3237 return;
3238 }
3239 fprintf(stderr, "Can't stop on free; address "FMTP" is not in a known block.\n", a);
3240 MEMENTO_UNLOCK();
3241 }
3242
3243 void Memento_breakOnRealloc(void *a)
3244 {
3245 findBlkData data;
3246
3247 MEMENTO_LOCK();
3248 data.addr = a;
3249 data.blk = NULL;
3250 data.flags = 0;
3251 Memento_appBlocks(&memento.used, Memento_containsAddr, &data);
3252 if (data.blk != NULL) {
3253 fprintf(stderr, "Will stop when address "FMTP" (in %sallocated block ",
3254 data.addr,
3255 (data.flags == 1 ? "" : (data.flags == 2 ?
3256 "preguard of " : "postguard of ")));
3257 showBlock(data.blk, ' ');
3258 fprintf(stderr, ") is freed (or realloced)\n");
3259 VALGRIND_MAKE_MEM_DEFINED(data.blk, sizeof(Memento_BlkHeader));
3260 data.blk->flags |= Memento_Flag_BreakOnFree | Memento_Flag_BreakOnRealloc;
3261 VALGRIND_MAKE_MEM_NOACCESS(data.blk, sizeof(Memento_BlkHeader));
3262 MEMENTO_UNLOCK();
3263 return;
3264 }
3265 data.blk = NULL;
3266 data.flags = 0;
3267 Memento_appBlocks(&memento.free, Memento_containsAddr, &data);
3268 if (data.blk != NULL) {
3269 fprintf(stderr, "Can't stop on free/realloc; address "FMTP" is in %sfreed block ",
3270 data.addr,
3271 (data.flags == 1 ? "" : (data.flags == 2 ?
3272 "preguard of " : "postguard of ")));
3273 showBlock(data.blk, ' ');
3274 fprintf(stderr, "\n");
3275 MEMENTO_UNLOCK();
3276 return;
3277 }
3278 fprintf(stderr, "Can't stop on free/realloc; address "FMTP" is not in a known block.\n", a);
3279 MEMENTO_UNLOCK();
3280 }
3281
3282 int Memento_failAt(int i)
3283 {
3284 memento.failAt = i;
3285 if ((memento.sequence > memento.failAt) &&
3286 (memento.failing != 0))
3287 Memento_startFailing();
3288 return i;
3289 }
3290
3291 size_t Memento_setMax(size_t max)
3292 {
3293 memento.maxMemory = max;
3294 return max;
3295 }
3296
3297 void Memento_startLeaking(void)
3298 {
3299 memento.leaking++;
3300 }
3301
3302 void Memento_stopLeaking(void)
3303 {
3304 memento.leaking--;
3305 }
3306
3307 int Memento_squeezing(void)
3308 {
3309 return memento.squeezing;
3310 }
3311
3312 #endif /* MEMENTO_CPP_EXTRAS_ONLY */
3313
3314 #ifdef __cplusplus
3315 /* Dumb overrides for the new and delete operators */
3316
3317 void *operator new(size_t size)
3318 {
3319 void *ret;
3320
3321 if (!memento.inited)
3322 Memento_init();
3323
3324 if (size == 0)
3325 size = 1;
3326 MEMENTO_LOCK();
3327 ret = do_malloc(size, Memento_EventType_new);
3328 MEMENTO_UNLOCK();
3329 return ret;
3330 }
3331
3332 void operator delete(void *pointer)
3333 {
3334 if (!pointer)
3335 return;
3336
3337 MEMENTO_LOCK();
3338 do_free(pointer, Memento_EventType_delete);
3339 MEMENTO_UNLOCK();
3340 }
3341
3342 /* Some C++ systems (apparently) don't provide new[] or delete[]
3343 * operators. Provide a way to cope with this */
3344 #ifndef MEMENTO_CPP_NO_ARRAY_CONSTRUCTORS
3345 void *operator new[](size_t size)
3346 {
3347 void *ret;
3348 if (!memento.inited)
3349 Memento_init();
3350
3351 if (size == 0)
3352 size = 1;
3353 MEMENTO_LOCK();
3354 ret = do_malloc(size, Memento_EventType_newArray);
3355 MEMENTO_UNLOCK();
3356 return ret;
3357 }
3358
3359 void operator delete[](void *pointer)
3360 {
3361 MEMENTO_LOCK();
3362 do_free(pointer, Memento_EventType_deleteArray);
3363 MEMENTO_UNLOCK();
3364 }
3365 #endif /* MEMENTO_CPP_NO_ARRAY_CONSTRUCTORS */
3366 #endif /* __cplusplus */
3367
3368 #else
3369
3370 /* Just in case anyone has left some debugging code in... */
3371 void (Memento_breakpoint)(void)
3372 {
3373 }
3374
3375 int (Memento_checkBlock)(void *b)
3376 {
3377 return 0;
3378 }
3379
3380 int (Memento_checkAllMemory)(void)
3381 {
3382 return 0;
3383 }
3384
3385 int (Memento_check)(void)
3386 {
3387 return 0;
3388 }
3389
3390 int (Memento_setParanoia)(int i)
3391 {
3392 return 0;
3393 }
3394
3395 int (Memento_paranoidAt)(int i)
3396 {
3397 return 0;
3398 }
3399
3400 int (Memento_breakAt)(int i)
3401 {
3402 return 0;
3403 }
3404
3405 int (Memento_getBlockNum)(void *i)
3406 {
3407 return 0;
3408 }
3409
3410 int (Memento_find)(void *a)
3411 {
3412 return 0;
3413 }
3414
3415 int (Memento_failAt)(int i)
3416 {
3417 return 0;
3418 }
3419
3420 void (Memento_breakOnFree)(void *a)
3421 {
3422 }
3423
3424 void (Memento_breakOnRealloc)(void *a)
3425 {
3426 }
3427
3428 void *(Memento_takeRef)(void *a)
3429 {
3430 return a;
3431 }
3432
3433 void *(Memento_dropRef)(void *a)
3434 {
3435 return a;
3436 }
3437
3438 void *(Memento_adjustRef)(void *a, int adjust)
3439 {
3440 return a;
3441 }
3442
3443 void *(Memento_reference)(void *a)
3444 {
3445 return a;
3446 }
3447
3448 #undef Memento_malloc
3449 #undef Memento_free
3450 #undef Memento_realloc
3451 #undef Memento_calloc
3452 #undef Memento_strdup
3453
3454 void *Memento_malloc(size_t size)
3455 {
3456 return MEMENTO_UNDERLYING_MALLOC(size);
3457 }
3458
3459 void Memento_free(void *b)
3460 {
3461 MEMENTO_UNDERLYING_FREE(b);
3462 }
3463
3464 void *Memento_realloc(void *b, size_t s)
3465 {
3466 return MEMENTO_UNDERLYING_REALLOC(b, s);
3467 }
3468
3469 void *Memento_calloc(size_t n, size_t s)
3470 {
3471 return MEMENTO_UNDERLYING_CALLOC(n, s);
3472 }
3473
3474 /* Avoid calling strdup, in case our compiler doesn't support it.
3475 * Yes, I'm looking at you, early Visual Studios. */
3476 char *Memento_strdup(const char *s)
3477 {
3478 size_t len = strlen(s)+1;
3479 char *ret = MEMENTO_UNDERLYING_MALLOC(len);
3480 if (ret != NULL)
3481 memcpy(ret, s, len);
3482 return ret;
3483 }
3484
3485 /* Avoid calling asprintf, in case our compiler doesn't support it.
3486 * Vaguely unhappy about relying on vsnprintf, but... */
3487 int Memento_asprintf(char **ret, const char *format, ...)
3488 {
3489 va_list va;
3490 int n;
3491 int n2;
3492
3493 va_start(va, format);
3494 n = vsnprintf(NULL, 0, format, va);
3495 va_end(va);
3496 if (n < 0)
3497 return n;
3498
3499 *ret = MEMENTO_UNDERLYING_MALLOC(n+1);
3500 if (*ret == NULL)
3501 return -1;
3502
3503 va_start(va, format);
3504 n2 = vsnprintf(*ret, n + 1, format, va);
3505 va_end(va);
3506
3507 return n2;
3508 }
3509
3510 /* Avoid calling vasprintf, in case our compiler doesn't support it.
3511 * Vaguely unhappy about relying on vsnprintf, but... */
3512 int Memento_vasprintf(char **ret, const char *format, va_list ap)
3513 {
3514 int n;
3515 va_list ap2;
3516 va_copy(ap2, ap);
3517
3518 n = vsnprintf(NULL, 0, format, ap);
3519 if (n < 0) {
3520 va_end(ap2);
3521 return n;
3522 }
3523
3524 *ret = MEMENTO_UNDERLYING_MALLOC(n+1);
3525 if (*ret == NULL) {
3526 va_end(ap2);
3527 return -1;
3528 }
3529
3530 n = vsnprintf(*ret, n + 1, format, ap2);
3531 va_end(ap2);
3532
3533 return n;
3534 }
3535
3536 void (Memento_listBlocks)(void)
3537 {
3538 }
3539
3540 void (Memento_listNewBlocks)(void)
3541 {
3542 }
3543
3544 size_t (Memento_setMax)(size_t max)
3545 {
3546 return 0;
3547 }
3548
3549 void (Memento_stats)(void)
3550 {
3551 }
3552
3553 void *(Memento_label)(void *ptr, const char *label)
3554 {
3555 return ptr;
3556 }
3557
3558 void (Memento_info)(void *addr)
3559 {
3560 }
3561
3562 void (Memento_listBlockInfo)(void)
3563 {
3564 }
3565
3566 void (Memento_startLeaking)(void)
3567 {
3568 }
3569
3570 void (Memento_stopLeaking)(void)
3571 {
3572 }
3573
3574 int (Memento_squeezing)(void)
3575 {
3576 return 0;
3577 }
3578
3579 #endif