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