Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/source/fitz/memento.c @ 3:2c135c81b16c
MERGE: upstream PyMuPDF 1.26.4 with MuPDF 1.26.7
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:44:09 +0200 |
| parents | b50eed0cc0ef |
| children |
comparison
equal
deleted
inserted
replaced
| 0:6015a75abc2d | 3:2c135c81b16c |
|---|---|
| 1 /* Copyright (C) 2009-2024 Artifex Software, Inc. | |
| 2 All Rights Reserved. | |
| 3 | |
| 4 This software is provided AS-IS with no warranty, either express or | |
| 5 implied. | |
| 6 | |
| 7 This software is distributed under license and may not be copied, | |
| 8 modified or distributed except as expressly authorized under the terms | |
| 9 of the license contained in the file COPYING in this distribution. | |
| 10 | |
| 11 Refer to licensing information at http://www.artifex.com or contact | |
| 12 Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, | |
| 13 CA 94129, USA, for further information. | |
| 14 */ | |
| 15 | |
| 16 #ifndef MEMENTO_CPP_EXTRAS_ONLY | |
| 17 | |
| 18 /* Inspired by Fortify by Simon P Bullen. */ | |
| 19 | |
| 20 /* Set the following if we want to do a build specifically for memory | |
| 21 * squeezing. We sacrifice some features for speed. */ | |
| 22 /* #define MEMENTO_SQUEEZEBUILD */ | |
| 23 | |
| 24 /* Set the following if you're only looking for leaks, not memory overwrites | |
| 25 * to speed the operation */ | |
| 26 /* #define MEMENTO_LEAKONLY */ | |
| 27 | |
| 28 /* Unset the following if you don't want the speed/memory hit of tracking references. */ | |
| 29 #ifndef MEMENTO_SQUEEZEBUILD | |
| 30 #define MEMENTO_TRACKREFS | |
| 31 #endif | |
| 32 | |
| 33 /* Set the following to keep extra details about the history of blocks */ | |
| 34 #ifndef MEMENTO_SQUEEZEBUILD | |
| 35 #define MEMENTO_DETAILS | |
| 36 #endif | |
| 37 | |
| 38 /* Set what volume of memory blocks we keep around after it's been freed | |
| 39 * to check for overwrites. */ | |
| 40 #define MEMENTO_FREELIST_MAX 0x2000000 | |
| 41 | |
| 42 /* Don't keep blocks around if they'd mean losing more than a quarter of | |
| 43 * the freelist. */ | |
| 44 #define MEMENTO_FREELIST_MAX_SINGLE_BLOCK (MEMENTO_FREELIST_MAX/4) | |
| 45 | |
| 46 #define COMPILING_MEMENTO_C | |
| 47 | |
| 48 /* SHUT UP, MSVC. I KNOW WHAT I AM DOING. */ | |
| 49 #define _CRT_SECURE_NO_WARNINGS | |
| 50 | |
| 51 /* We have some GS specific tweaks; more for the GS build environment than | |
| 52 * anything else. */ | |
| 53 /* #define MEMENTO_GS_HACKS */ | |
| 54 | |
| 55 #ifdef MEMENTO_GS_HACKS | |
| 56 /* For GS we include malloc_.h. Anyone else would just include memento.h */ | |
| 57 #include "malloc_.h" | |
| 58 #include "memory_.h" | |
| 59 int atexit(void (*)(void)); | |
| 60 #else | |
| 61 #ifdef MEMENTO_MUPDF_HACKS | |
| 62 #include "mupdf/memento.h" | |
| 63 #else | |
| 64 #include "memento.h" | |
| 65 #endif | |
| 66 #include <stdio.h> | |
| 67 #endif | |
| 68 #ifndef _MSC_VER | |
| 69 #include <stdint.h> | |
| 70 #include <limits.h> | |
| 71 #include <unistd.h> | |
| 72 #endif | |
| 73 | |
| 74 #include <errno.h> | |
| 75 #include <stdlib.h> | |
| 76 #include <stdarg.h> | |
| 77 #include <string.h> | |
| 78 | |
| 79 #ifdef __ANDROID__ | |
| 80 #define MEMENTO_ANDROID | |
| 81 #include <stdio.h> | |
| 82 #endif | |
| 83 | |
| 84 /* Workaround VS2012 (and earlier) missing va_copy. */ | |
| 85 #ifdef _MSC_VER | |
| 86 # if _MSC_VER < 1800 /* Prior to 2013 */ | |
| 87 # ifndef va_copy | |
| 88 # ifdef __va_copy | |
| 89 # define va_copy(dst,src) __va_copy(dst,src) | |
| 90 # else | |
| 91 # define va_copy(dst,src) memcpy(&dst, &src, sizeof(va_list)) | |
| 92 # endif /* __va_copy */ | |
| 93 # endif /* va_copy */ | |
| 94 # endif | |
| 95 #endif | |
| 96 | |
| 97 /* Hacks to portably print large sizes */ | |
| 98 #ifdef _MSC_VER | |
| 99 #define FMTZ "%llu" | |
| 100 #define FMTZ_CAST _int64 | |
| 101 #define FMTP "0x%p" | |
| 102 typedef unsigned _int64 mem_uint64_t; | |
| 103 #else | |
| 104 #define FMTZ "%zu" | |
| 105 #define FMTZ_CAST size_t | |
| 106 #define FMTP "%p" | |
| 107 typedef long long mem_uint64_t; | |
| 108 #endif | |
| 109 | |
| 110 #define UB(x) ((intptr_t)((x) & 0xFF)) | |
| 111 #define B2I(x) (UB(x) | (UB(x)<<8) | (UB(x)<<16) | (UB(x)<<24)) | |
| 112 #define B2P(x) ((void *)(B2I(x) | ((B2I(x)<<16)<<16))) | |
| 113 #define MEMENTO_PREFILL_UBYTE ((unsigned char)(MEMENTO_PREFILL)) | |
| 114 #define MEMENTO_PREFILL_USHORT (((unsigned short)MEMENTO_PREFILL_UBYTE) | (((unsigned short)MEMENTO_PREFILL_UBYTE)<<8)) | |
| 115 #define MEMENTO_PREFILL_UINT (((unsigned int)MEMENTO_PREFILL_USHORT) | (((unsigned int)MEMENTO_PREFILL_USHORT)<<16)) | |
| 116 #define MEMENTO_PREFILL_PTR (void *)(((uintptr_t)MEMENTO_PREFILL_UINT) | ((((uintptr_t)MEMENTO_PREFILL_UINT)<<16)<<16)) | |
| 117 #define MEMENTO_POSTFILL_UBYTE ((unsigned char)(MEMENTO_POSTFILL)) | |
| 118 #define MEMENTO_POSTFILL_USHORT (((unsigned short)MEMENTO_POSTFILL_UBYTE) | (((unsigned short)MEMENTO_POSTFILL_UBYTE)<<8)) | |
| 119 #define MEMENTO_POSTFILL_UINT (((unsigned int)MEMENTO_POSTFILL_USHORT) | (((unsigned int)MEMENTO_POSTFILL_USHORT)<<16)) | |
| 120 #define MEMENTO_POSTFILL_PTR (void *)(((uintptr_t)MEMENTO_POSTFILL_UINT) | ((((uintptr_t)MEMENTO_POSTFILL_UINT)<<16)<<16)) | |
| 121 #define MEMENTO_ALLOCFILL_UBYTE ((unsigned char)(MEMENTO_ALLOCFILL)) | |
| 122 #define MEMENTO_ALLOCFILL_USHORT (((unsigned short)MEMENTO_ALLOCFILL_UBYTE) | (((unsigned short)MEMENTO_ALLOCFILL_UBYTE)<<8)) | |
| 123 #define MEMENTO_ALLOCFILL_UINT (((unsigned int)MEMENTO_ALLOCFILL_USHORT) | (((unsigned int)MEMENTO_ALLOCFILL_USHORT)<<16)) | |
| 124 #define MEMENTO_ALLOCFILL_PTR (void *)(((uintptr_t)MEMENTO_ALLOCFILL_UINT) | ((((uintptr_t)MEMENTO_ALLOCFILL_UINT)<<16)<<16)) | |
| 125 #define MEMENTO_FREEFILL_UBYTE ((unsigned char)(MEMENTO_FREEFILL)) | |
| 126 #define MEMENTO_FREEFILL_USHORT (((unsigned short)MEMENTO_FREEFILL_UBYTE) | (((unsigned short)MEMENTO_FREEFILL_UBYTE)<<8)) | |
| 127 #define MEMENTO_FREEFILL_UINT (((unsigned int)MEMENTO_FREEFILL_USHORT) | (((unsigned int)MEMENTO_FREEFILL_USHORT)<<16)) | |
| 128 #define MEMENTO_FREEFILL_PTR (void *)(((uintptr_t)MEMENTO_FREEFILL_UINT) | ((((uintptr_t)MEMENTO_FREEFILL_UINT)<<16)<<16)) | |
| 129 | |
| 130 #ifdef MEMENTO | |
| 131 | |
| 132 #ifdef MEMENTO_ANDROID | |
| 133 #include <android/log.h> | |
| 134 | |
| 135 static char log_buffer[4096]; | |
| 136 static int log_fill = 0; | |
| 137 | |
| 138 static char log_buffer2[4096]; | |
| 139 | |
| 140 static int | |
| 141 android_fprintf(FILE *file, const char *fmt, ...) | |
| 142 { | |
| 143 va_list args; | |
| 144 char *p, *q; | |
| 145 | |
| 146 va_start(args, fmt); | |
| 147 vsnprintf(log_buffer2, sizeof(log_buffer2)-1, fmt, args); | |
| 148 va_end(args); | |
| 149 | |
| 150 /* Ensure we are always null terminated */ | |
| 151 log_buffer2[sizeof(log_buffer2)-1] = 0; | |
| 152 | |
| 153 p = log_buffer2; | |
| 154 q = p; | |
| 155 do | |
| 156 { | |
| 157 /* Find the end of the string, or the next \n */ | |
| 158 while (*p && *p != '\n') | |
| 159 p++; | |
| 160 | |
| 161 /* We need to output from q to p. Limit ourselves to what | |
| 162 * will fit in the existing */ | |
| 163 if (p - q >= sizeof(log_buffer)-1 - log_fill) | |
| 164 p = q + sizeof(log_buffer)-1 - log_fill; | |
| 165 | |
| 166 memcpy(&log_buffer[log_fill], q, p-q); | |
| 167 log_fill += p-q; | |
| 168 if (*p == '\n') | |
| 169 { | |
| 170 log_buffer[log_fill] = 0; | |
| 171 __android_log_print(ANDROID_LOG_ERROR, "memento", "%s", log_buffer); | |
| 172 usleep(1); | |
| 173 log_fill = 0; | |
| 174 p++; /* Skip over the \n */ | |
| 175 } | |
| 176 else if (log_fill >= sizeof(log_buffer)-1) | |
| 177 { | |
| 178 log_buffer[sizeof(log_buffer2)-1] = 0; | |
| 179 __android_log_print(ANDROID_LOG_ERROR, "memento", "%s", log_buffer); | |
| 180 usleep(1); | |
| 181 log_fill = 0; | |
| 182 } | |
| 183 q = p; | |
| 184 } | |
| 185 while (*p); | |
| 186 | |
| 187 return 0; | |
| 188 } | |
| 189 | |
| 190 #define fprintf android_fprintf | |
| 191 #define MEMENTO_STACKTRACE_METHOD 3 | |
| 192 #endif | |
| 193 | |
| 194 /* _WIN64 defined implies _WIN32 will be */ | |
| 195 #ifdef _WIN32 | |
| 196 #include <windows.h> | |
| 197 | |
| 198 static int | |
| 199 windows_fprintf(FILE *file, const char *fmt, ...) | |
| 200 { | |
| 201 va_list args; | |
| 202 char text[4096]; | |
| 203 int ret; | |
| 204 | |
| 205 va_start(args, fmt); | |
| 206 ret = vfprintf(file, fmt, args); | |
| 207 va_end(args); | |
| 208 | |
| 209 va_start(args, fmt); | |
| 210 vsnprintf(text, 4096, fmt, args); | |
| 211 OutputDebugStringA(text); | |
| 212 va_end(args); | |
| 213 | |
| 214 return ret; | |
| 215 } | |
| 216 | |
| 217 #define fprintf windows_fprintf | |
| 218 #endif | |
| 219 | |
| 220 #ifndef MEMENTO_STACKTRACE_METHOD | |
| 221 #ifdef __GNUC__ | |
| 222 #define MEMENTO_STACKTRACE_METHOD 1 | |
| 223 #endif | |
| 224 #ifdef _WIN32 | |
| 225 #define MEMENTO_STACKTRACE_METHOD 2 | |
| 226 #endif | |
| 227 #endif | |
| 228 | |
| 229 #if defined(__linux__) || defined(__OpenBSD__) | |
| 230 #define MEMENTO_HAS_FORK | |
| 231 #elif defined(__APPLE__) && defined(__MACH__) | |
| 232 #define MEMENTO_HAS_FORK | |
| 233 #endif | |
| 234 | |
| 235 #if defined(_DLL) && defined(_MSC_VER) | |
| 236 #define MEMENTO_CRT_SPEC __declspec(dllimport) | |
| 237 #else | |
| 238 #define MEMENTO_CRT_SPEC | |
| 239 #endif | |
| 240 | |
| 241 /* Define the underlying allocators, just in case */ | |
| 242 MEMENTO_CRT_SPEC void *MEMENTO_UNDERLYING_MALLOC(size_t); | |
| 243 MEMENTO_CRT_SPEC void MEMENTO_UNDERLYING_FREE(void *); | |
| 244 MEMENTO_CRT_SPEC void *MEMENTO_UNDERLYING_REALLOC(void *,size_t); | |
| 245 MEMENTO_CRT_SPEC void *MEMENTO_UNDERLYING_CALLOC(size_t,size_t); | |
| 246 | |
| 247 /* And some other standard functions we use. We don't include the header | |
| 248 * files, just in case they pull in unexpected others. */ | |
| 249 MEMENTO_CRT_SPEC int atoi(const char *); | |
| 250 MEMENTO_CRT_SPEC char *getenv(const char *); | |
| 251 | |
| 252 /* How far to search for pointers in each block when calculating nestings */ | |
| 253 /* mupdf needs at least 34000ish (sizeof(fz_shade))/ */ | |
| 254 #define MEMENTO_PTRSEARCH 65536 | |
| 255 | |
| 256 #ifndef MEMENTO_MAXPATTERN | |
| 257 #define MEMENTO_MAXPATTERN 0 | |
| 258 #endif | |
| 259 | |
| 260 #ifdef MEMENTO_GS_HACKS | |
| 261 #include "valgrind.h" | |
| 262 #else | |
| 263 #ifdef HAVE_VALGRIND | |
| 264 #include "valgrind/memcheck.h" | |
| 265 #else | |
| 266 #define VALGRIND_MAKE_MEM_NOACCESS(p,s) do { } while (0==1) | |
| 267 #define VALGRIND_MAKE_MEM_UNDEFINED(p,s) do { } while (0==1) | |
| 268 #define VALGRIND_MAKE_MEM_DEFINED(p,s) do { } while (0==1) | |
| 269 #endif | |
| 270 #endif | |
| 271 | |
| 272 enum { | |
| 273 Memento_PreSize = 16, | |
| 274 Memento_PostSize = 16 | |
| 275 }; | |
| 276 | |
| 277 /* Some compile time checks */ | |
| 278 typedef struct | |
| 279 { | |
| 280 char MEMENTO_PRESIZE_MUST_BE_A_MULTIPLE_OF_4[Memento_PreSize & 3 ? -1 : 1]; | |
| 281 char MEMENTO_POSTSIZE_MUST_BE_A_MULTIPLE_OF_4[Memento_PostSize & 3 ? -1 : 1]; | |
| 282 char MEMENTO_POSTSIZE_MUST_BE_AT_LEAST_4[Memento_PostSize >= 4 ? 1 : -1]; | |
| 283 char MEMENTO_PRESIZE_MUST_BE_AT_LEAST_4[Memento_PreSize >= 4 ? 1 : -1]; | |
| 284 } MEMENTO_SANITY_CHECK_STRUCT; | |
| 285 | |
| 286 #define MEMENTO_UINT32 unsigned int | |
| 287 #define MEMENTO_UINT16 unsigned short | |
| 288 | |
| 289 #define MEMENTO_PREFILL_UINT32 ((MEMENTO_UINT32)(MEMENTO_PREFILL | (MEMENTO_PREFILL <<8) | (MEMENTO_PREFILL <<16) |(MEMENTO_PREFILL <<24))) | |
| 290 #define MEMENTO_POSTFILL_UINT16 ((MEMENTO_UINT16)(MEMENTO_POSTFILL | (MEMENTO_POSTFILL<<8))) | |
| 291 #define MEMENTO_POSTFILL_UINT32 ((MEMENTO_UINT32)(MEMENTO_POSTFILL | (MEMENTO_POSTFILL<<8) | (MEMENTO_POSTFILL<<16) |(MEMENTO_POSTFILL<<24))) | |
| 292 #define MEMENTO_FREEFILL_UINT16 ((MEMENTO_UINT16)(MEMENTO_FREEFILL | (MEMENTO_FREEFILL<<8))) | |
| 293 #define MEMENTO_FREEFILL_UINT32 ((MEMENTO_UINT32)(MEMENTO_FREEFILL | (MEMENTO_FREEFILL<<8) | (MEMENTO_FREEFILL<<16) |(MEMENTO_FREEFILL<<24))) | |
| 294 | |
| 295 enum { | |
| 296 Memento_Flag_OldBlock = 1, | |
| 297 Memento_Flag_HasParent = 2, | |
| 298 Memento_Flag_BreakOnFree = 4, | |
| 299 Memento_Flag_BreakOnRealloc = 8, | |
| 300 Memento_Flag_Freed = 16, | |
| 301 Memento_Flag_KnownLeak = 32, | |
| 302 Memento_Flag_Reported = 64, | |
| 303 Memento_Flag_LastPhase = 0x80000000, | |
| 304 Memento_Flag_PhaseMask = 0xFFFF0000 | |
| 305 }; | |
| 306 | |
| 307 enum { | |
| 308 Memento_EventType_malloc = 0, | |
| 309 Memento_EventType_calloc = 1, | |
| 310 Memento_EventType_realloc = 2, | |
| 311 Memento_EventType_free = 3, | |
| 312 Memento_EventType_new = 4, | |
| 313 Memento_EventType_delete = 5, | |
| 314 Memento_EventType_newArray = 6, | |
| 315 Memento_EventType_deleteArray = 7, | |
| 316 Memento_EventType_takeRef = 8, | |
| 317 Memento_EventType_dropRef = 9, | |
| 318 Memento_EventType_reference = 10, | |
| 319 Memento_EventType_strdup = 11, | |
| 320 Memento_EventType_asprintf = 12, | |
| 321 Memento_EventType_vasprintf = 13 | |
| 322 }; | |
| 323 | |
| 324 static const char *eventType[] = | |
| 325 { | |
| 326 "malloc", | |
| 327 "calloc", | |
| 328 "realloc", | |
| 329 "free", | |
| 330 "new", | |
| 331 "delete", | |
| 332 "new[]", | |
| 333 "delete[]", | |
| 334 "takeRef", | |
| 335 "dropRef", | |
| 336 "reference", | |
| 337 "strdup", | |
| 338 "asprintf", | |
| 339 "vasprintf" | |
| 340 }; | |
| 341 | |
| 342 /* When we list leaked blocks at the end of execution, we search for pointers | |
| 343 * between blocks in order to be able to give a nice nested view. | |
| 344 * Unfortunately, if you have are running your own allocator (such as | |
| 345 * postscript's chunk allocator) you can often find that the header of the | |
| 346 * block always contains pointers to next or previous blocks. This tends to | |
| 347 * mean the nesting displayed is "uninteresting" at best :) | |
| 348 * | |
| 349 * As a hack to get around this, we have a define MEMENTO_SKIP_SEARCH that | |
| 350 * indicates how many bytes to skip over at the start of the chunk. | |
| 351 * This may cause us to miss true nestings, but such is life... | |
| 352 */ | |
| 353 #ifndef MEMENTO_SEARCH_SKIP | |
| 354 #ifdef MEMENTO_GS_HACKS | |
| 355 #define MEMENTO_SEARCH_SKIP (2*sizeof(void *)) | |
| 356 #else | |
| 357 #define MEMENTO_SEARCH_SKIP 0 | |
| 358 #endif | |
| 359 #endif | |
| 360 | |
| 361 #define MEMENTO_CHILD_MAGIC ((Memento_BlkHeader *)('M' | ('3' << 8) | ('m' << 16) | ('3' << 24))) | |
| 362 #define MEMENTO_SIBLING_MAGIC ((Memento_BlkHeader *)('n' | ('t' << 8) | ('0' << 16) | ('!' << 24))) | |
| 363 | |
| 364 #ifdef MEMENTO_DETAILS | |
| 365 typedef struct Memento_hashedST Memento_hashedST; | |
| 366 | |
| 367 struct Memento_hashedST | |
| 368 { | |
| 369 Memento_hashedST *next; | |
| 370 MEMENTO_UINT32 hash; | |
| 371 int count; | |
| 372 void *trace[1]; | |
| 373 }; | |
| 374 | |
| 375 typedef struct Memento_BlkDetails Memento_BlkDetails; | |
| 376 | |
| 377 struct Memento_BlkDetails | |
| 378 { | |
| 379 Memento_BlkDetails *next; | |
| 380 char type; | |
| 381 int sequence; | |
| 382 Memento_hashedST *trace; | |
| 383 }; | |
| 384 #endif /* MEMENTO_DETAILS */ | |
| 385 | |
| 386 typedef struct Memento_BlkHeader Memento_BlkHeader; | |
| 387 | |
| 388 struct Memento_BlkHeader | |
| 389 { | |
| 390 size_t rawsize; | |
| 391 int sequence; | |
| 392 int lastCheckedOK; | |
| 393 int flags; | |
| 394 | |
| 395 const char *label; | |
| 396 | |
| 397 /* Blocks are held in a linked list for LRU */ | |
| 398 Memento_BlkHeader *next; | |
| 399 Memento_BlkHeader *prev; /* Reused as 'parent' when printing nested list */ | |
| 400 | |
| 401 /* Blocks are held in a splay tree for position. */ | |
| 402 Memento_BlkHeader *parent; | |
| 403 Memento_BlkHeader *left; | |
| 404 Memento_BlkHeader *right; | |
| 405 | |
| 406 /* Entries for nesting display calculations. Set to magic | |
| 407 * values at all other time. */ | |
| 408 Memento_BlkHeader *child; | |
| 409 Memento_BlkHeader *sibling; | |
| 410 | |
| 411 #ifdef MEMENTO_DETAILS | |
| 412 Memento_BlkDetails *details; | |
| 413 Memento_BlkDetails **details_tail; | |
| 414 #endif | |
| 415 | |
| 416 /* On 64bit versions of windows, we need blocks to be returned | |
| 417 * from malloc as 128bit aligned due to setjmp. Hence, add a | |
| 418 * dummy padding block to make the entire struct a multiple of | |
| 419 * 128bits. This has to go before the preblk. */ | |
| 420 #if defined(WIN64) | |
| 421 void *dummy; | |
| 422 #endif | |
| 423 | |
| 424 char preblk[Memento_PreSize]; | |
| 425 }; | |
| 426 | |
| 427 /* In future this could (should) be a smarter data structure, like, say, | |
| 428 * splay trees. For now, we use a list. | |
| 429 */ | |
| 430 typedef struct Memento_Blocks | |
| 431 { | |
| 432 Memento_BlkHeader *head; | |
| 433 Memento_BlkHeader *tail; | |
| 434 Memento_BlkHeader *top; | |
| 435 } Memento_Blocks; | |
| 436 | |
| 437 /* What sort of Mutex should we use? */ | |
| 438 #ifdef MEMENTO_LOCKLESS | |
| 439 typedef int Memento_mutex; | |
| 440 | |
| 441 static void Memento_initMutex(Memento_mutex *m) | |
| 442 { | |
| 443 (void)m; | |
| 444 } | |
| 445 | |
| 446 #define MEMENTO_DO_LOCK() do { } while (0) | |
| 447 #define MEMENTO_DO_UNLOCK() do { } while (0) | |
| 448 | |
| 449 #else | |
| 450 #if defined(_WIN32) || defined(_WIN64) | |
| 451 /* Windows */ | |
| 452 typedef CRITICAL_SECTION Memento_mutex; | |
| 453 | |
| 454 static void Memento_initMutex(Memento_mutex *m) | |
| 455 { | |
| 456 InitializeCriticalSection(m); | |
| 457 } | |
| 458 | |
| 459 #define MEMENTO_DO_LOCK() \ | |
| 460 EnterCriticalSection(&memento.mutex) | |
| 461 #define MEMENTO_DO_UNLOCK() \ | |
| 462 LeaveCriticalSection(&memento.mutex) | |
| 463 | |
| 464 #else | |
| 465 #include <pthread.h> | |
| 466 typedef pthread_mutex_t Memento_mutex; | |
| 467 | |
| 468 static void Memento_initMutex(Memento_mutex *m) | |
| 469 { | |
| 470 pthread_mutex_init(m, NULL); | |
| 471 } | |
| 472 | |
| 473 #define MEMENTO_DO_LOCK() \ | |
| 474 pthread_mutex_lock(&memento.mutex) | |
| 475 #define MEMENTO_DO_UNLOCK() \ | |
| 476 pthread_mutex_unlock(&memento.mutex) | |
| 477 | |
| 478 #endif | |
| 479 #endif | |
| 480 | |
| 481 typedef struct { | |
| 482 int begin; | |
| 483 int end; | |
| 484 } Memento_range; | |
| 485 | |
| 486 /* And our global structure */ | |
| 487 static struct { | |
| 488 int inited; | |
| 489 Memento_Blocks used; | |
| 490 Memento_Blocks free; | |
| 491 size_t freeListSize; | |
| 492 int sequence; | |
| 493 int paranoia; | |
| 494 int paranoidAt; | |
| 495 int countdown; | |
| 496 int lastChecked; | |
| 497 int breakAt; | |
| 498 int failAt; | |
| 499 int failing; | |
| 500 int nextFailAt; | |
| 501 int squeezeAt; | |
| 502 int squeezing; | |
| 503 int segv; | |
| 504 int pattern; | |
| 505 int nextPattern; | |
| 506 int patternBit; | |
| 507 int leaking; | |
| 508 int showDetailedBlocks; | |
| 509 int hideMultipleReallocs; | |
| 510 int hideRefChangeBacktraces; | |
| 511 int abortOnLeak; | |
| 512 int abortOnCorruption; | |
| 513 size_t maxMemory; | |
| 514 size_t alloc; | |
| 515 size_t peakAlloc; | |
| 516 mem_uint64_t totalAlloc; | |
| 517 size_t numMallocs; | |
| 518 size_t numFrees; | |
| 519 size_t numReallocs; | |
| 520 Memento_mutex mutex; | |
| 521 Memento_range *squeezes; | |
| 522 int squeezes_num; | |
| 523 int squeezes_pos; | |
| 524 int ignoreNewDelete; | |
| 525 int atexitFin; | |
| 526 int phasing; | |
| 527 int verbose; | |
| 528 int verboseNewlineSuppressed; | |
| 529 void *lastVerbosePtr; | |
| 530 char **backtraceLimitFnnames; | |
| 531 int backtraceLimitFnnamesNum; | |
| 532 #ifdef MEMENTO_DETAILS | |
| 533 Memento_hashedST *stacktraces[256]; | |
| 534 int hashCollisions; | |
| 535 #endif | |
| 536 } memento; | |
| 537 | |
| 538 #define MEMENTO_EXTRASIZE (sizeof(Memento_BlkHeader) + Memento_PostSize) | |
| 539 | |
| 540 /* Round up size S to the next multiple of N (where N is a power of 2) */ | |
| 541 #define MEMENTO_ROUNDUP(S,N) ((S + N-1)&~(N-1)) | |
| 542 | |
| 543 #define MEMBLK_SIZE(s) MEMENTO_ROUNDUP(s + MEMENTO_EXTRASIZE, MEMENTO_MAXALIGN) | |
| 544 | |
| 545 #define MEMBLK_FROMBLK(B) (&((Memento_BlkHeader*)(void *)(B))[-1]) | |
| 546 #define MEMBLK_TOBLK(B) ((void*)(&((Memento_BlkHeader*)(void*)(B))[1])) | |
| 547 #define MEMBLK_POSTPTR(B) \ | |
| 548 (&((unsigned char *)(void *)(B))[(B)->rawsize + sizeof(Memento_BlkHeader)]) | |
| 549 | |
| 550 enum | |
| 551 { | |
| 552 SkipStackBackTraceLevels = 4 | |
| 553 }; | |
| 554 | |
| 555 #if defined(MEMENTO_STACKTRACE_METHOD) && MEMENTO_STACKTRACE_METHOD == 1 | |
| 556 extern size_t backtrace(void **, int); | |
| 557 extern void backtrace_symbols_fd(void **, size_t, int); | |
| 558 extern char **backtrace_symbols(void **, size_t); | |
| 559 | |
| 560 #define MEMENTO_BACKTRACE_MAX 256 | |
| 561 static int (*print_stack_value)(void *address); | |
| 562 | |
| 563 /* Libbacktrace gubbins - relies on us having libdl to load the .so */ | |
| 564 #ifdef HAVE_LIBDL | |
| 565 #include <dlfcn.h> | |
| 566 | |
| 567 typedef void (*backtrace_error_callback) (void *data, const char *msg, int errnum); | |
| 568 | |
| 569 typedef struct backtrace_state *(*backtrace_create_state_type)( | |
| 570 const char *filename, int threaded, | |
| 571 backtrace_error_callback error_callback, void *data); | |
| 572 | |
| 573 typedef int (*backtrace_full_callback) (void *data, uintptr_t pc, | |
| 574 const char *filename, int lineno, | |
| 575 const char *function); | |
| 576 | |
| 577 typedef int (*backtrace_pcinfo_type)(struct backtrace_state *state, | |
| 578 uintptr_t pc, | |
| 579 backtrace_full_callback callback, | |
| 580 backtrace_error_callback error_callback, | |
| 581 void *data); | |
| 582 | |
| 583 typedef void (*backtrace_syminfo_callback) (void *data, uintptr_t pc, | |
| 584 const char *symname, | |
| 585 uintptr_t symval, | |
| 586 uintptr_t symsize); | |
| 587 | |
| 588 typedef int (*backtrace_syminfo_type)(struct backtrace_state *state, | |
| 589 uintptr_t addr, | |
| 590 backtrace_syminfo_callback callback, | |
| 591 backtrace_error_callback error_callback, | |
| 592 void *data); | |
| 593 | |
| 594 static backtrace_syminfo_type backtrace_syminfo; | |
| 595 static backtrace_create_state_type backtrace_create_state; | |
| 596 static backtrace_pcinfo_type backtrace_pcinfo; | |
| 597 static struct backtrace_state *my_backtrace_state; | |
| 598 static void *libbt; | |
| 599 static char backtrace_exe[4096]; | |
| 600 static void *current_addr; | |
| 601 | |
| 602 static void error2_cb(void *data, const char *msg, int errnum) | |
| 603 { | |
| 604 (void)data; | |
| 605 (void)msg; | |
| 606 (void)errnum; | |
| 607 } | |
| 608 | |
| 609 static void syminfo_cb(void *data, uintptr_t pc, const char *symname, uintptr_t symval, uintptr_t symsize) | |
| 610 { | |
| 611 (void)data; | |
| 612 (void)symval; | |
| 613 (void)symsize; | |
| 614 if (sizeof(void *) == 4) | |
| 615 fprintf(stderr, " 0x%08lx %s\n", pc, symname?symname:"?"); | |
| 616 else | |
| 617 fprintf(stderr, " 0x%016lx %s\n", pc, symname?symname:"?"); | |
| 618 } | |
| 619 | |
| 620 static void error_cb(void *data, const char *msg, int errnum) | |
| 621 { | |
| 622 (void)data; | |
| 623 (void)msg; | |
| 624 (void)errnum; | |
| 625 backtrace_syminfo(my_backtrace_state, | |
| 626 (uintptr_t)current_addr, | |
| 627 syminfo_cb, | |
| 628 error2_cb, | |
| 629 NULL); | |
| 630 } | |
| 631 | |
| 632 static int full_cb(void *data, uintptr_t pc, const char *fname, int line, const char *fn) | |
| 633 { | |
| 634 if (sizeof(void *) == 4) | |
| 635 fprintf(stderr, " 0x%08lx %s(%s:%d)\n", pc, fn?fn:"?", fname?fname:"?", line); | |
| 636 else | |
| 637 fprintf(stderr, " 0x%016lx %s(%s:%d)\n", pc, fn?fn:"?", fname?fname:"?", line); | |
| 638 if (fn) { | |
| 639 int i; | |
| 640 for (i=0; i<memento.backtraceLimitFnnamesNum; ++i) { | |
| 641 if (!strcmp(fn, memento.backtraceLimitFnnames[i])) { | |
| 642 *(int*) data = 1; | |
| 643 } | |
| 644 } | |
| 645 } | |
| 646 return 0; | |
| 647 } | |
| 648 | |
| 649 static int print_stack_libbt(void *addr) | |
| 650 { | |
| 651 int end = 0; | |
| 652 current_addr = addr; | |
| 653 backtrace_pcinfo(my_backtrace_state, | |
| 654 (uintptr_t)addr, | |
| 655 full_cb, | |
| 656 error_cb, | |
| 657 &end); | |
| 658 return end; | |
| 659 } | |
| 660 | |
| 661 static int print_stack_libbt_failed(void *addr) | |
| 662 { | |
| 663 char **strings; | |
| 664 #if 0 | |
| 665 /* Let's use a hack from Julian Smith to call gdb to extract the information */ | |
| 666 /* Disabled for now, as I can't make this work. */ | |
| 667 static char command[1024]; | |
| 668 int e; | |
| 669 static int gdb_invocation_failed = 0; | |
| 670 | |
| 671 if (gdb_invocation_failed == 0) | |
| 672 { | |
| 673 snprintf(command, sizeof(command), | |
| 674 //"gdb -q --batch -p=%i -ex 'info line *%p' -ex quit 2>/dev/null", | |
| 675 "gdb -q --batch -p=%i -ex 'info line *%p' -ex quit 2>/dev/null| egrep -v '(Thread debugging using)|(Using host libthread_db library)|(A debugging session is active)|(will be detached)|(Quit anyway)|(No such file or directory)|(^0x)|(^$)'", | |
| 676 getpid(), addr); | |
| 677 printf("%s\n", command); | |
| 678 e = system(command); | |
| 679 if (e == 0) | |
| 680 return; /* That'll do! */ | |
| 681 gdb_invocation_failed = 1; /* If it's failed once, it'll probably keep failing. */ | |
| 682 } | |
| 683 #endif | |
| 684 | |
| 685 /* We couldn't even get gdb! Make do. */ | |
| 686 strings = backtrace_symbols(&addr, 1); | |
| 687 | |
| 688 if (strings == NULL || strings[0] == NULL) | |
| 689 { | |
| 690 if (sizeof(void *) == 4) | |
| 691 fprintf(stderr, " [0x%08lx]\n", (uintptr_t)addr); | |
| 692 else | |
| 693 fprintf(stderr, " [0x%016lx]\n", (uintptr_t)addr); | |
| 694 } | |
| 695 else | |
| 696 { | |
| 697 fprintf(stderr, " %s\n", strings[0]); | |
| 698 } | |
| 699 (free)(strings); | |
| 700 return 0; | |
| 701 } | |
| 702 | |
| 703 static int init_libbt(void) | |
| 704 { | |
| 705 static int libbt_inited = 0; | |
| 706 | |
| 707 if (libbt_inited) | |
| 708 return 0; | |
| 709 libbt_inited = 1; | |
| 710 | |
| 711 libbt = dlopen("libbacktrace.so", RTLD_LAZY); | |
| 712 if (libbt == NULL) | |
| 713 libbt = dlopen("/opt/lib/libbacktrace.so", RTLD_LAZY); | |
| 714 if (libbt == NULL) | |
| 715 libbt = dlopen("/lib/libbacktrace.so", RTLD_LAZY); | |
| 716 if (libbt == NULL) | |
| 717 libbt = dlopen("/usr/lib/libbacktrace.so", RTLD_LAZY); | |
| 718 if (libbt == NULL) | |
| 719 libbt = dlopen("/usr/local/lib/libbacktrace.so", RTLD_LAZY); | |
| 720 if (libbt == NULL) | |
| 721 goto fail; | |
| 722 | |
| 723 backtrace_create_state = dlsym(libbt, "backtrace_create_state"); | |
| 724 backtrace_syminfo = dlsym(libbt, "backtrace_syminfo"); | |
| 725 backtrace_pcinfo = dlsym(libbt, "backtrace_pcinfo"); | |
| 726 | |
| 727 if (backtrace_create_state == NULL || | |
| 728 backtrace_syminfo == NULL || | |
| 729 backtrace_pcinfo == NULL) | |
| 730 { | |
| 731 goto fail; | |
| 732 } | |
| 733 | |
| 734 my_backtrace_state = backtrace_create_state(backtrace_exe, | |
| 735 1 /*BACKTRACE_SUPPORTS_THREADS*/, | |
| 736 error_cb, | |
| 737 NULL); | |
| 738 if (my_backtrace_state == NULL) | |
| 739 goto fail; | |
| 740 | |
| 741 print_stack_value = print_stack_libbt; | |
| 742 | |
| 743 return 1; | |
| 744 | |
| 745 fail: | |
| 746 fprintf(stderr, | |
| 747 "MEMENTO: libbacktrace.so failed to load; backtraces will be sparse.\n" | |
| 748 "MEMENTO: See memento.h for how to rectify this.\n"); | |
| 749 libbt = NULL; | |
| 750 backtrace_create_state = NULL; | |
| 751 backtrace_syminfo = NULL; | |
| 752 print_stack_value = print_stack_libbt_failed; | |
| 753 return 0; | |
| 754 } | |
| 755 #endif | |
| 756 | |
| 757 static int print_stack_default(void *addr) | |
| 758 { | |
| 759 char **strings = backtrace_symbols(&addr, 1); | |
| 760 | |
| 761 if (strings == NULL || strings[0] == NULL) | |
| 762 { | |
| 763 fprintf(stderr, " ["FMTP"]\n", addr); | |
| 764 } | |
| 765 #ifdef HAVE_LIBDL | |
| 766 else if (strchr(strings[0], ':') == NULL) | |
| 767 { | |
| 768 /* Probably a "path [address]" format string */ | |
| 769 char *s = strchr(strings[0], ' '); | |
| 770 | |
| 771 if (s != strings[0]) | |
| 772 { | |
| 773 memcpy(backtrace_exe, strings[0], s - strings[0]); | |
| 774 backtrace_exe[s-strings[0]] = 0; | |
| 775 init_libbt(); | |
| 776 print_stack_value(addr); | |
| 777 } | |
| 778 } | |
| 779 #endif | |
| 780 else | |
| 781 { | |
| 782 fprintf(stderr, " %s\n", strings[0]); | |
| 783 } | |
| 784 free(strings); | |
| 785 return 0; | |
| 786 } | |
| 787 | |
| 788 static void Memento_initStacktracer(void) | |
| 789 { | |
| 790 print_stack_value = print_stack_default; | |
| 791 } | |
| 792 | |
| 793 static int Memento_getStacktrace(void **stack, int *skip) | |
| 794 { | |
| 795 size_t num; | |
| 796 | |
| 797 num = backtrace(&stack[0], MEMENTO_BACKTRACE_MAX); | |
| 798 | |
| 799 *skip = SkipStackBackTraceLevels; | |
| 800 if (num <= SkipStackBackTraceLevels) | |
| 801 return 0; | |
| 802 return (int)(num-SkipStackBackTraceLevels); | |
| 803 } | |
| 804 | |
| 805 static void Memento_showStacktrace(void **stack, int numberOfFrames) | |
| 806 { | |
| 807 int i; | |
| 808 | |
| 809 for (i = 0; i < numberOfFrames; i++) | |
| 810 { | |
| 811 if (print_stack_value(stack[i])) | |
| 812 break; | |
| 813 } | |
| 814 } | |
| 815 #elif defined(MEMENTO_STACKTRACE_METHOD) && MEMENTO_STACKTRACE_METHOD == 2 | |
| 816 #include <Windows.h> | |
| 817 | |
| 818 /* We use DbgHelp.dll rather than DbgHelp.lib. This avoids us needing | |
| 819 * extra link time complications, and enables us to fall back gracefully | |
| 820 * if the DLL cannot be found. | |
| 821 * | |
| 822 * To achieve this we have our own potted versions of the required types | |
| 823 * inline here. | |
| 824 */ | |
| 825 #ifdef _WIN64 | |
| 826 typedef DWORD64 DWORD_NATIVESIZED; | |
| 827 #else | |
| 828 typedef DWORD DWORD_NATIVESIZED; | |
| 829 #endif | |
| 830 | |
| 831 #define MEMENTO_BACKTRACE_MAX 64 | |
| 832 | |
| 833 typedef USHORT (__stdcall *My_CaptureStackBackTraceType)(__in ULONG, __in ULONG, __out PVOID*, __out_opt PULONG); | |
| 834 | |
| 835 typedef struct MY_IMAGEHLP_LINE { | |
| 836 DWORD SizeOfStruct; | |
| 837 PVOID Key; | |
| 838 DWORD LineNumber; | |
| 839 PCHAR FileName; | |
| 840 DWORD_NATIVESIZED Address; | |
| 841 } MY_IMAGEHLP_LINE, *MY_PIMAGEHLP_LINE; | |
| 842 | |
| 843 typedef BOOL (__stdcall *My_SymGetLineFromAddrType)(HANDLE hProcess, DWORD_NATIVESIZED dwAddr, PDWORD pdwDisplacement, MY_PIMAGEHLP_LINE Line); | |
| 844 | |
| 845 typedef struct MY_SYMBOL_INFO { | |
| 846 ULONG SizeOfStruct; | |
| 847 ULONG TypeIndex; // Type Index of symbol | |
| 848 ULONG64 Reserved[2]; | |
| 849 ULONG info; | |
| 850 ULONG Size; | |
| 851 ULONG64 ModBase; // Base Address of module containing this symbol | |
| 852 ULONG Flags; | |
| 853 ULONG64 Value; // Value of symbol, ValuePresent should be 1 | |
| 854 ULONG64 Address; // Address of symbol including base address of module | |
| 855 ULONG Register; // register holding value or pointer to value | |
| 856 ULONG Scope; // scope of the symbol | |
| 857 ULONG Tag; // pdb classification | |
| 858 ULONG NameLen; // Actual length of name | |
| 859 ULONG MaxNameLen; | |
| 860 CHAR Name[1]; // Name of symbol | |
| 861 } MY_SYMBOL_INFO, *MY_PSYMBOL_INFO; | |
| 862 | |
| 863 typedef BOOL (__stdcall *My_SymFromAddrType)(HANDLE hProcess, DWORD64 Address, PDWORD64 Displacement, MY_PSYMBOL_INFO Symbol); | |
| 864 typedef BOOL (__stdcall *My_SymInitializeType)(HANDLE hProcess, PSTR UserSearchPath, BOOL fInvadeProcess); | |
| 865 | |
| 866 static My_CaptureStackBackTraceType Memento_CaptureStackBackTrace; | |
| 867 static My_SymGetLineFromAddrType Memento_SymGetLineFromAddr; | |
| 868 static My_SymFromAddrType Memento_SymFromAddr; | |
| 869 static My_SymInitializeType Memento_SymInitialize; | |
| 870 static HANDLE Memento_process; | |
| 871 | |
| 872 static void Memento_initStacktracer(void) | |
| 873 { | |
| 874 HMODULE mod = LoadLibrary("kernel32.dll"); | |
| 875 | |
| 876 if (mod == NULL) | |
| 877 return; | |
| 878 Memento_CaptureStackBackTrace = (My_CaptureStackBackTraceType)(GetProcAddress(mod, "RtlCaptureStackBackTrace")); | |
| 879 if (Memento_CaptureStackBackTrace == NULL) | |
| 880 return; | |
| 881 mod = LoadLibrary("Dbghelp.dll"); | |
| 882 if (mod == NULL) { | |
| 883 Memento_CaptureStackBackTrace = NULL; | |
| 884 return; | |
| 885 } | |
| 886 Memento_SymGetLineFromAddr = | |
| 887 (My_SymGetLineFromAddrType)(GetProcAddress(mod, | |
| 888 #ifdef _WIN64 | |
| 889 "SymGetLineFromAddr64" | |
| 890 #else | |
| 891 "SymGetLineFromAddr" | |
| 892 #endif | |
| 893 )); | |
| 894 if (Memento_SymGetLineFromAddr == NULL) { | |
| 895 Memento_CaptureStackBackTrace = NULL; | |
| 896 return; | |
| 897 } | |
| 898 Memento_SymFromAddr = (My_SymFromAddrType)(GetProcAddress(mod, "SymFromAddr")); | |
| 899 if (Memento_SymFromAddr == NULL) { | |
| 900 Memento_CaptureStackBackTrace = NULL; | |
| 901 return; | |
| 902 } | |
| 903 Memento_SymInitialize = (My_SymInitializeType)(GetProcAddress(mod, "SymInitialize")); | |
| 904 if (Memento_SymInitialize == NULL) { | |
| 905 Memento_CaptureStackBackTrace = NULL; | |
| 906 return; | |
| 907 } | |
| 908 Memento_process = GetCurrentProcess(); | |
| 909 Memento_SymInitialize(Memento_process, NULL, TRUE); | |
| 910 } | |
| 911 | |
| 912 static int Memento_getStacktrace(void **stack, int *skip) | |
| 913 { | |
| 914 if (Memento_CaptureStackBackTrace == NULL) | |
| 915 return 0; | |
| 916 | |
| 917 *skip = 0; | |
| 918 /* Limit us to 63 levels due to windows bug */ | |
| 919 return Memento_CaptureStackBackTrace(SkipStackBackTraceLevels, 63-SkipStackBackTraceLevels, stack, NULL); | |
| 920 } | |
| 921 | |
| 922 static void Memento_showStacktrace(void **stack, int numberOfFrames) | |
| 923 { | |
| 924 MY_IMAGEHLP_LINE line; | |
| 925 int i, j; | |
| 926 char symbol_buffer[sizeof(MY_SYMBOL_INFO) + 1024 + 1]; | |
| 927 MY_SYMBOL_INFO *symbol = (MY_SYMBOL_INFO *)symbol_buffer; | |
| 928 BOOL ok; | |
| 929 int prefix = 1; /* Ignore a prefix of 'unknowns' */ | |
| 930 int suppressed = 0; /* How many unknowns we have suppressed. */ | |
| 931 | |
| 932 symbol->MaxNameLen = 1024; | |
| 933 symbol->SizeOfStruct = sizeof(MY_SYMBOL_INFO); | |
| 934 line.SizeOfStruct = sizeof(MY_IMAGEHLP_LINE); | |
| 935 for (i = 0; i < numberOfFrames; i++) | |
| 936 { | |
| 937 DWORD64 dwDisplacement64; | |
| 938 DWORD dwDisplacement; | |
| 939 ok = Memento_SymFromAddr(Memento_process, (DWORD64)(stack[i]), &dwDisplacement64, symbol); | |
| 940 if (ok == 1) | |
| 941 ok = Memento_SymGetLineFromAddr(Memento_process, (DWORD_NATIVESIZED)(stack[i]), &dwDisplacement, &line); | |
| 942 if (ok == 1) { | |
| 943 for (j = 0; j < suppressed; j++) | |
| 944 fprintf(stderr, " unknown\n"); | |
| 945 suppressed = 0; | |
| 946 fprintf(stderr, " %s in %s:%d\n", symbol->Name, line.FileName, line.LineNumber); | |
| 947 prefix = 0; | |
| 948 } else if (prefix == 0) { | |
| 949 suppressed++; | |
| 950 } | |
| 951 } | |
| 952 } | |
| 953 #elif defined(MEMENTO_STACKTRACE_METHOD) && MEMENTO_STACKTRACE_METHOD == 3 | |
| 954 | |
| 955 #include <unwind.h> | |
| 956 #include <dlfcn.h> | |
| 957 | |
| 958 /* From cxxabi.h */ | |
| 959 extern char* __cxa_demangle(const char* mangled_name, | |
| 960 char* output_buffer, | |
| 961 size_t* length, | |
| 962 int* status); | |
| 963 | |
| 964 static void Memento_initStacktracer(void) | |
| 965 { | |
| 966 } | |
| 967 | |
| 968 #define MEMENTO_BACKTRACE_MAX 256 | |
| 969 | |
| 970 typedef struct | |
| 971 { | |
| 972 int count; | |
| 973 void **addr; | |
| 974 } my_unwind_details; | |
| 975 | |
| 976 static _Unwind_Reason_Code unwind_populate_callback(struct _Unwind_Context *context, | |
| 977 void *arg) | |
| 978 { | |
| 979 my_unwind_details *uw = (my_unwind_details *)arg; | |
| 980 int count = uw->count; | |
| 981 | |
| 982 if (count >= MEMENTO_BACKTRACE_MAX) | |
| 983 return _URC_END_OF_STACK; | |
| 984 | |
| 985 uw->addr[count] = (void *)_Unwind_GetIP(context); | |
| 986 uw->count++; | |
| 987 | |
| 988 return _URC_NO_REASON; | |
| 989 } | |
| 990 | |
| 991 static int Memento_getStacktrace(void **stack, int *skip) | |
| 992 { | |
| 993 my_unwind_details uw = { 0, stack }; | |
| 994 | |
| 995 *skip = 0; | |
| 996 | |
| 997 /* Collect the backtrace. Deliberately only unwind once, | |
| 998 * and avoid using malloc etc until this completes just | |
| 999 * in case. */ | |
| 1000 _Unwind_Backtrace(unwind_populate_callback, &uw); | |
| 1001 if (uw.count <= SkipStackBackTraceLevels) | |
| 1002 return 0; | |
| 1003 | |
| 1004 *skip = SkipStackBackTraceLevels; | |
| 1005 return uw.count-SkipStackBackTraceLevels; | |
| 1006 } | |
| 1007 | |
| 1008 static void Memento_showStacktrace(void **stack, int numberOfFrames) | |
| 1009 { | |
| 1010 int i; | |
| 1011 | |
| 1012 for (i = 0; i < numberOfFrames; i++) | |
| 1013 { | |
| 1014 Dl_info info; | |
| 1015 if (dladdr(stack[i], &info)) | |
| 1016 { | |
| 1017 int status = 0; | |
| 1018 const char *sym = info.dli_sname ? info.dli_sname : "<unknown>"; | |
| 1019 char *demangled = __cxa_demangle(sym, NULL, 0, &status); | |
| 1020 int offset = stack[i] - info.dli_saddr; | |
| 1021 fprintf(stderr, " ["FMTP"]%s(+0x%x)\n", stack[i], demangled && status == 0 ? demangled : sym, offset); | |
| 1022 free(demangled); | |
| 1023 } | |
| 1024 else | |
| 1025 { | |
| 1026 fprintf(stderr, " ["FMTP"]\n", stack[i]); | |
| 1027 } | |
| 1028 } | |
| 1029 } | |
| 1030 | |
| 1031 #else | |
| 1032 static void Memento_initStacktracer(void) | |
| 1033 { | |
| 1034 } | |
| 1035 | |
| 1036 static int Memento_getStacktrace(void **stack, int *skip) | |
| 1037 { | |
| 1038 *skip = 0; | |
| 1039 return 0; | |
| 1040 } | |
| 1041 | |
| 1042 static void Memento_showStacktrace(void **stack, int numberOfFrames) | |
| 1043 { | |
| 1044 } | |
| 1045 #endif /* MEMENTO_STACKTRACE_METHOD */ | |
| 1046 | |
| 1047 #ifndef MEMENTO_BACKTRACE_MAX | |
| 1048 #define MEMENTO_BACKTRACE_MAX 1 | |
| 1049 #endif | |
| 1050 | |
| 1051 #ifdef MEMENTO_DETAILS | |
| 1052 static MEMENTO_UINT32 | |
| 1053 hashStackTrace(void **stack, int count) | |
| 1054 { | |
| 1055 int i; | |
| 1056 MEMENTO_UINT32 hash = 0; | |
| 1057 | |
| 1058 count *= sizeof(void *)/sizeof(unsigned int); | |
| 1059 for (i = 0; i < count; i++) | |
| 1060 hash = (hash>>5) ^ (hash<<27) ^ ((unsigned int *)stack)[i]; | |
| 1061 | |
| 1062 return hash; | |
| 1063 } | |
| 1064 | |
| 1065 static Memento_hashedST oom_hashed_st = | |
| 1066 { | |
| 1067 NULL, /* next */ | |
| 1068 0, /* hash */ | |
| 1069 0, /* count */ | |
| 1070 {NULL}/* trace[0] */ | |
| 1071 }; | |
| 1072 | |
| 1073 static Memento_hashedST *Memento_getHashedStacktrace(void) | |
| 1074 { | |
| 1075 void *stack[MEMENTO_BACKTRACE_MAX]; | |
| 1076 MEMENTO_UINT32 hash; | |
| 1077 int count, skip; | |
| 1078 Memento_hashedST **h; | |
| 1079 | |
| 1080 #ifdef MEMENTO_STACKTRACE_METHOD | |
| 1081 count = Memento_getStacktrace(stack, &skip); | |
| 1082 #else | |
| 1083 skip = 0; | |
| 1084 count = 0; | |
| 1085 #endif | |
| 1086 | |
| 1087 count -= skip; | |
| 1088 hash = hashStackTrace(&stack[skip], count); | |
| 1089 while (1) { | |
| 1090 h = &memento.stacktraces[hash & 0xff]; | |
| 1091 while (*h) { | |
| 1092 if ((*h)->hash == hash) | |
| 1093 break; | |
| 1094 h = &(*h)->next; | |
| 1095 } | |
| 1096 if ((*h) == NULL) | |
| 1097 break; /* No match, fall through to make a new one. */ | |
| 1098 if (count == (*h)->count && | |
| 1099 memcmp((*h)->trace, &stack[skip], sizeof(void *) * count) == 0) | |
| 1100 return (*h); /* We match! Reuse this one. */ | |
| 1101 /* Hash collision. */ | |
| 1102 hash++; | |
| 1103 memento.hashCollisions++; | |
| 1104 } | |
| 1105 | |
| 1106 (*h) = MEMENTO_UNDERLYING_MALLOC(sizeof(Memento_hashedST) + sizeof(void *) * (count-1)); | |
| 1107 if (*h == NULL) | |
| 1108 return &oom_hashed_st; | |
| 1109 | |
| 1110 (*h)->next = NULL; | |
| 1111 (*h)->hash = hash; | |
| 1112 (*h)->count = count; | |
| 1113 memcpy(&(*h)->trace[0], &stack[skip], count * sizeof(void *)); | |
| 1114 | |
| 1115 return *h; | |
| 1116 } | |
| 1117 | |
| 1118 static void Memento_showHashedStacktrace(Memento_hashedST *trace) | |
| 1119 { | |
| 1120 if (trace == NULL) | |
| 1121 return; | |
| 1122 | |
| 1123 Memento_showStacktrace(&trace->trace[0], trace->count); | |
| 1124 } | |
| 1125 | |
| 1126 static void Memento_storeDetails(Memento_BlkHeader *head, int type, Memento_hashedST *st) | |
| 1127 { | |
| 1128 Memento_BlkDetails *details; | |
| 1129 | |
| 1130 if (head == NULL) | |
| 1131 return; | |
| 1132 | |
| 1133 details = MEMENTO_UNDERLYING_MALLOC(sizeof(*details)); | |
| 1134 if (details == NULL) | |
| 1135 return; | |
| 1136 | |
| 1137 details->type = (char)type; | |
| 1138 details->sequence = memento.sequence; | |
| 1139 details->next = NULL; | |
| 1140 details->trace = st; | |
| 1141 VALGRIND_MAKE_MEM_DEFINED(&head->details_tail, sizeof(head->details_tail)); | |
| 1142 *head->details_tail = details; | |
| 1143 head->details_tail = &details->next; | |
| 1144 VALGRIND_MAKE_MEM_NOACCESS(&head->details_tail, sizeof(head->details_tail)); | |
| 1145 } | |
| 1146 #endif | |
| 1147 | |
| 1148 void Memento_showHash(MEMENTO_UINT32 hash) | |
| 1149 { | |
| 1150 #ifdef MEMENTO_DETAILS | |
| 1151 Memento_hashedST *h; | |
| 1152 | |
| 1153 h = memento.stacktraces[hash & 0xff]; | |
| 1154 while (h) { | |
| 1155 if (h->hash == hash) | |
| 1156 break; | |
| 1157 h = h->next; | |
| 1158 } | |
| 1159 | |
| 1160 Memento_showHashedStacktrace(h); | |
| 1161 #endif | |
| 1162 } | |
| 1163 | |
| 1164 static void Memento_bt_internal(int skip2) | |
| 1165 { | |
| 1166 #ifdef MEMENTO_STACKTRACE_METHOD | |
| 1167 void *stack[MEMENTO_BACKTRACE_MAX]; | |
| 1168 int count; | |
| 1169 int skip; | |
| 1170 | |
| 1171 count = Memento_getStacktrace(stack, &skip); | |
| 1172 Memento_showStacktrace(&stack[skip+skip2], count-skip-skip2); | |
| 1173 #endif | |
| 1174 } | |
| 1175 | |
| 1176 void (Memento_bt)(void) | |
| 1177 { | |
| 1178 Memento_bt_internal(0); | |
| 1179 } | |
| 1180 | |
| 1181 static int Memento_checkAllMemoryLocked(void); | |
| 1182 | |
| 1183 void Memento_breakpoint(void) | |
| 1184 { | |
| 1185 /* A handy externally visible function for breakpointing */ | |
| 1186 #if 0 /* Enable this to force automatic breakpointing */ | |
| 1187 #ifndef NDEBUG | |
| 1188 #ifdef _MSC_VER | |
| 1189 __asm int 3; | |
| 1190 #endif | |
| 1191 #endif | |
| 1192 #endif | |
| 1193 } | |
| 1194 | |
| 1195 static void Memento_init(void); | |
| 1196 | |
| 1197 #define MEMENTO_LOCK() \ | |
| 1198 do { if (!memento.inited) Memento_init(); MEMENTO_DO_LOCK(); } while (0) | |
| 1199 | |
| 1200 #define MEMENTO_UNLOCK() \ | |
| 1201 do { MEMENTO_DO_UNLOCK(); } while (0) | |
| 1202 | |
| 1203 /* Do this as a macro to prevent another level in the callstack, | |
| 1204 * which is annoying while stepping. */ | |
| 1205 #define Memento_breakpointLocked() \ | |
| 1206 do { MEMENTO_UNLOCK(); Memento_breakpoint(); MEMENTO_LOCK(); } while (0) | |
| 1207 | |
| 1208 /* Move the given node to the root of the tree, by | |
| 1209 * performing a series of the following rotations. | |
| 1210 * The key observation here is that all these | |
| 1211 * rotations preserve the ordering of the tree, and | |
| 1212 * result in 'x' getting higher. | |
| 1213 * | |
| 1214 * Case 1: z x Case 1b: z x | |
| 1215 * # # # # # # # # | |
| 1216 * y D A y A y y D | |
| 1217 * # # => # # # # => # # | |
| 1218 * x C B z B x z C | |
| 1219 * # # # # # # # # | |
| 1220 * A B C D C D A B | |
| 1221 * | |
| 1222 * Case 2: z x Case 2b: z x | |
| 1223 * # # ## ## # # ## ## | |
| 1224 * y D y z A y z y | |
| 1225 * # # => # # # # # # => # # # # | |
| 1226 * A x A B C D x D A B C D | |
| 1227 * # # # # | |
| 1228 * B C B C | |
| 1229 * | |
| 1230 * Case 3: y x Case 3b: y x | |
| 1231 * # # # # # # # # | |
| 1232 * x C => A y A x => y C | |
| 1233 * # # # # # # # # | |
| 1234 * A B B C B C A B | |
| 1235 */ | |
| 1236 static void | |
| 1237 move_to_root(Memento_BlkHeader *x) | |
| 1238 { | |
| 1239 Memento_BlkHeader *y, *z; | |
| 1240 | |
| 1241 if (x == NULL) | |
| 1242 return; | |
| 1243 | |
| 1244 VALGRIND_MAKE_MEM_DEFINED(x, sizeof(*x)); | |
| 1245 while ((y = x->parent) != NULL) { | |
| 1246 VALGRIND_MAKE_MEM_DEFINED(y, sizeof(*y)); | |
| 1247 if ((z = y->parent) != NULL) { | |
| 1248 VALGRIND_MAKE_MEM_DEFINED(z, sizeof(*z)); | |
| 1249 x->parent = z->parent; | |
| 1250 if (x->parent) { | |
| 1251 VALGRIND_MAKE_MEM_DEFINED(x->parent, sizeof(*x->parent)); | |
| 1252 if (x->parent->left == z) | |
| 1253 x->parent->left = x; | |
| 1254 else | |
| 1255 x->parent->right = x; | |
| 1256 VALGRIND_MAKE_MEM_NOACCESS(x->parent, sizeof(*x->parent)); | |
| 1257 } | |
| 1258 y->parent = x; | |
| 1259 /* Case 1, 1b, 2 or 2b */ | |
| 1260 if (y->left == x) { | |
| 1261 /* Case 1 or 2b */ | |
| 1262 if (z->left == y) { | |
| 1263 /* Case 1 */ | |
| 1264 y->left = x->right; | |
| 1265 if (y->left) { | |
| 1266 VALGRIND_MAKE_MEM_DEFINED(y->left, sizeof(*y->left)); | |
| 1267 y->left->parent = y; | |
| 1268 VALGRIND_MAKE_MEM_NOACCESS(y->left, sizeof(*y->left)); | |
| 1269 } | |
| 1270 z->left = y->right; | |
| 1271 if (z->left) { | |
| 1272 VALGRIND_MAKE_MEM_DEFINED(z->left, sizeof(*z->left)); | |
| 1273 z->left->parent = z; | |
| 1274 VALGRIND_MAKE_MEM_NOACCESS(z->left, sizeof(*z->left)); | |
| 1275 } | |
| 1276 y->right = z; | |
| 1277 z->parent = y; | |
| 1278 } else { | |
| 1279 /* Case 2b */ | |
| 1280 z->right = x->left; | |
| 1281 if (z->right) { | |
| 1282 VALGRIND_MAKE_MEM_DEFINED(z->right, sizeof(*z->right)); | |
| 1283 z->right->parent = z; | |
| 1284 VALGRIND_MAKE_MEM_NOACCESS(z->right, sizeof(*z->right)); | |
| 1285 } | |
| 1286 y->left = x->right; | |
| 1287 if (y->left) { | |
| 1288 VALGRIND_MAKE_MEM_DEFINED(y->left, sizeof(*y->left)); | |
| 1289 y->left->parent = y; | |
| 1290 VALGRIND_MAKE_MEM_NOACCESS(y->left, sizeof(*y->left)); | |
| 1291 } | |
| 1292 x->left = z; | |
| 1293 z->parent = x; | |
| 1294 } | |
| 1295 x->right = y; | |
| 1296 } else { | |
| 1297 /* Case 2 or 1b */ | |
| 1298 if (z->left == y) { | |
| 1299 /* Case 2 */ | |
| 1300 y->right = x->left; | |
| 1301 if (y->right) { | |
| 1302 VALGRIND_MAKE_MEM_DEFINED(y->right, sizeof(*y->right)); | |
| 1303 y->right->parent = y; | |
| 1304 VALGRIND_MAKE_MEM_NOACCESS(y->right, sizeof(*y->right)); | |
| 1305 } | |
| 1306 z->left = x->right; | |
| 1307 if (z->left) { | |
| 1308 VALGRIND_MAKE_MEM_DEFINED(z->left, sizeof(*z->left)); | |
| 1309 z->left->parent = z; | |
| 1310 VALGRIND_MAKE_MEM_NOACCESS(z->left, sizeof(*z->left)); | |
| 1311 } | |
| 1312 x->right = z; | |
| 1313 z->parent = x; | |
| 1314 } else { | |
| 1315 /* Case 1b */ | |
| 1316 z->right = y->left; | |
| 1317 if (z->right) { | |
| 1318 VALGRIND_MAKE_MEM_DEFINED(z->right, sizeof(*z->right)); | |
| 1319 z->right->parent = z; | |
| 1320 VALGRIND_MAKE_MEM_NOACCESS(z->right, sizeof(*z->right)); | |
| 1321 } | |
| 1322 y->right = x->left; | |
| 1323 if (y->right) { | |
| 1324 VALGRIND_MAKE_MEM_DEFINED(y->right, sizeof(*y->right)); | |
| 1325 y->right->parent = y; | |
| 1326 VALGRIND_MAKE_MEM_NOACCESS(y->right, sizeof(*y->right)); | |
| 1327 } | |
| 1328 y->left = z; | |
| 1329 z->parent = y; | |
| 1330 } | |
| 1331 x->left = y; | |
| 1332 } | |
| 1333 VALGRIND_MAKE_MEM_NOACCESS(z, sizeof(*z)); | |
| 1334 } else { | |
| 1335 /* Case 3 or 3b */ | |
| 1336 x->parent = NULL; | |
| 1337 y->parent = x; | |
| 1338 if (y->left == x) { | |
| 1339 /* Case 3 */ | |
| 1340 y->left = x->right; | |
| 1341 if (y->left) { | |
| 1342 VALGRIND_MAKE_MEM_DEFINED(y->left, sizeof(*y->left)); | |
| 1343 y->left->parent = y; | |
| 1344 VALGRIND_MAKE_MEM_NOACCESS(y->left, sizeof(*y->left)); | |
| 1345 } | |
| 1346 x->right = y; | |
| 1347 } else { | |
| 1348 /* Case 3b */ | |
| 1349 y->right = x->left; | |
| 1350 if (y->right) { | |
| 1351 VALGRIND_MAKE_MEM_DEFINED(y->right, sizeof(*y->right)); | |
| 1352 y->right->parent = y; | |
| 1353 VALGRIND_MAKE_MEM_NOACCESS(y->right, sizeof(*y->right)); | |
| 1354 } | |
| 1355 x->left = y; | |
| 1356 } | |
| 1357 } | |
| 1358 VALGRIND_MAKE_MEM_NOACCESS(y, sizeof(*y)); | |
| 1359 } | |
| 1360 VALGRIND_MAKE_MEM_NOACCESS(x, sizeof(*x)); | |
| 1361 } | |
| 1362 | |
| 1363 static void Memento_removeBlockSplay(Memento_Blocks *blks, | |
| 1364 Memento_BlkHeader *b) | |
| 1365 { | |
| 1366 Memento_BlkHeader *replacement; | |
| 1367 | |
| 1368 VALGRIND_MAKE_MEM_DEFINED(b, sizeof(*b)); | |
| 1369 if (b->left == NULL) | |
| 1370 { | |
| 1371 /* At most one child - easy */ | |
| 1372 replacement = b->right; | |
| 1373 } | |
| 1374 else if (b->right == NULL) | |
| 1375 { | |
| 1376 /* Strictly one child - easy */ | |
| 1377 replacement = b->left; | |
| 1378 } | |
| 1379 else | |
| 1380 { | |
| 1381 /* 2 Children - tricky */ | |
| 1382 /* Find in-order predecessor to b */ | |
| 1383 replacement = b->left; | |
| 1384 VALGRIND_MAKE_MEM_DEFINED(replacement, sizeof(*replacement)); | |
| 1385 while (replacement->right) | |
| 1386 { | |
| 1387 Memento_BlkHeader *o = replacement; | |
| 1388 replacement = o->right; | |
| 1389 VALGRIND_MAKE_MEM_DEFINED(replacement, sizeof(*replacement)); | |
| 1390 VALGRIND_MAKE_MEM_NOACCESS(o, sizeof(*o)); | |
| 1391 } | |
| 1392 /* Remove replacement - easy as just one child */ | |
| 1393 (void)Memento_removeBlockSplay(NULL, replacement); | |
| 1394 /* Replace b with replacement */ | |
| 1395 VALGRIND_MAKE_MEM_DEFINED(b, sizeof(*b)); | |
| 1396 if (b->left) { | |
| 1397 VALGRIND_MAKE_MEM_DEFINED(b->left, sizeof(*b->left)); | |
| 1398 b->left->parent = replacement; | |
| 1399 VALGRIND_MAKE_MEM_NOACCESS(b->left, sizeof(*b->left)); | |
| 1400 } | |
| 1401 VALGRIND_MAKE_MEM_DEFINED(b->right, sizeof(*b->right)); | |
| 1402 b->right->parent = replacement; | |
| 1403 VALGRIND_MAKE_MEM_NOACCESS(b->right, sizeof(*b->right)); | |
| 1404 VALGRIND_MAKE_MEM_DEFINED(replacement, sizeof(*replacement)); | |
| 1405 replacement->left = b->left; | |
| 1406 replacement->right = b->right; | |
| 1407 } | |
| 1408 if (b->parent) | |
| 1409 { | |
| 1410 VALGRIND_MAKE_MEM_DEFINED(b->parent, sizeof(*b->parent)); | |
| 1411 if (b->parent->left == b) | |
| 1412 b->parent->left = replacement; | |
| 1413 else | |
| 1414 b->parent->right = replacement; | |
| 1415 VALGRIND_MAKE_MEM_NOACCESS(b->parent, sizeof(*b->parent)); | |
| 1416 } else { | |
| 1417 VALGRIND_MAKE_MEM_DEFINED(&blks->top, sizeof(blks->top)); | |
| 1418 blks->top = replacement; | |
| 1419 VALGRIND_MAKE_MEM_NOACCESS(&blks->top, sizeof(blks->top)); | |
| 1420 } | |
| 1421 if (replacement) | |
| 1422 { | |
| 1423 VALGRIND_MAKE_MEM_DEFINED(replacement, sizeof(*replacement)); | |
| 1424 replacement->parent = b->parent; | |
| 1425 VALGRIND_MAKE_MEM_NOACCESS(replacement, sizeof(*replacement)); | |
| 1426 } | |
| 1427 VALGRIND_MAKE_MEM_NOACCESS(b, sizeof(*b)); | |
| 1428 } | |
| 1429 | |
| 1430 static void Memento_addBlockSplay(Memento_Blocks *blks, | |
| 1431 Memento_BlkHeader *b) | |
| 1432 { | |
| 1433 Memento_BlkHeader *parent = NULL; | |
| 1434 Memento_BlkHeader **n = &blks->top; | |
| 1435 | |
| 1436 /* Walk down, looking for a place to put b. */ | |
| 1437 VALGRIND_MAKE_MEM_DEFINED(&blks->top, sizeof(blks->top)); | |
| 1438 while (*n != NULL) { | |
| 1439 Memento_BlkHeader *o = parent; | |
| 1440 VALGRIND_MAKE_MEM_DEFINED(*n, sizeof(**n)); | |
| 1441 parent = *n; | |
| 1442 if (o) VALGRIND_MAKE_MEM_NOACCESS(o, sizeof(*o)); | |
| 1443 VALGRIND_MAKE_MEM_DEFINED(parent, sizeof(*parent)); | |
| 1444 if (b < parent) | |
| 1445 n = &parent->left; | |
| 1446 else | |
| 1447 n = &parent->right; | |
| 1448 } | |
| 1449 /* Place b */ | |
| 1450 *n = b; | |
| 1451 if (parent) VALGRIND_MAKE_MEM_NOACCESS(parent, sizeof(*parent)); | |
| 1452 b->parent = parent; | |
| 1453 b->left = NULL; | |
| 1454 b->right = NULL; | |
| 1455 /* Now perform the splay magic */ | |
| 1456 move_to_root(b); | |
| 1457 /* This always leaves b at the top. */ | |
| 1458 blks->top = b; | |
| 1459 VALGRIND_MAKE_MEM_DEFINED(b, sizeof(*b)); | |
| 1460 b->parent = NULL; | |
| 1461 VALGRIND_MAKE_MEM_NOACCESS(b, sizeof(*b)); | |
| 1462 VALGRIND_MAKE_MEM_NOACCESS(&blks->top, sizeof(blks->top)); | |
| 1463 } | |
| 1464 | |
| 1465 static void Memento_addBlockHead(Memento_Blocks *blks, | |
| 1466 Memento_BlkHeader *b, | |
| 1467 int type) | |
| 1468 { | |
| 1469 Memento_addBlockSplay(blks, b); | |
| 1470 if (blks->tail == NULL) | |
| 1471 blks->tail = b; | |
| 1472 VALGRIND_MAKE_MEM_DEFINED(b, sizeof(*b)); | |
| 1473 b->next = blks->head; | |
| 1474 b->prev = NULL; | |
| 1475 if (blks->head) | |
| 1476 { | |
| 1477 VALGRIND_MAKE_MEM_DEFINED(&blks->head->prev, sizeof(blks->head->prev)); | |
| 1478 blks->head->prev = b; | |
| 1479 VALGRIND_MAKE_MEM_NOACCESS(&blks->head->prev, sizeof(blks->head->prev)); | |
| 1480 } | |
| 1481 blks->head = b; | |
| 1482 #ifndef MEMENTO_LEAKONLY | |
| 1483 memset(b->preblk, MEMENTO_PREFILL, Memento_PreSize); | |
| 1484 memset(MEMBLK_POSTPTR(b), MEMENTO_POSTFILL, Memento_PostSize); | |
| 1485 #endif | |
| 1486 VALGRIND_MAKE_MEM_NOACCESS(MEMBLK_POSTPTR(b), Memento_PostSize); | |
| 1487 if (type == 0) { /* malloc */ | |
| 1488 VALGRIND_MAKE_MEM_UNDEFINED(MEMBLK_TOBLK(b), b->rawsize); | |
| 1489 } else if (type == 1) { /* free */ | |
| 1490 VALGRIND_MAKE_MEM_NOACCESS(MEMBLK_TOBLK(b), b->rawsize); | |
| 1491 } | |
| 1492 VALGRIND_MAKE_MEM_NOACCESS(b, sizeof(Memento_BlkHeader)); | |
| 1493 } | |
| 1494 | |
| 1495 static void Memento_addBlockTail(Memento_Blocks *blks, | |
| 1496 Memento_BlkHeader *b, | |
| 1497 int type) | |
| 1498 { | |
| 1499 Memento_addBlockSplay(blks, b); | |
| 1500 VALGRIND_MAKE_MEM_DEFINED(&blks->tail, sizeof(Memento_BlkHeader *)); | |
| 1501 if (blks->head == NULL) | |
| 1502 blks->head = b; | |
| 1503 VALGRIND_MAKE_MEM_DEFINED(b, sizeof(*b)); | |
| 1504 b->prev = blks->tail; | |
| 1505 b->next = NULL; | |
| 1506 if (blks->tail) { | |
| 1507 VALGRIND_MAKE_MEM_DEFINED(&blks->tail->next, sizeof(blks->tail->next)); | |
| 1508 blks->tail->next = b; | |
| 1509 VALGRIND_MAKE_MEM_NOACCESS(&blks->tail->next, sizeof(blks->tail->next)); | |
| 1510 } | |
| 1511 blks->tail = b; | |
| 1512 #ifndef MEMENTO_LEAKONLY | |
| 1513 memset(b->preblk, MEMENTO_PREFILL, Memento_PreSize); | |
| 1514 memset(MEMBLK_POSTPTR(b), MEMENTO_POSTFILL, Memento_PostSize); | |
| 1515 #endif | |
| 1516 VALGRIND_MAKE_MEM_NOACCESS(MEMBLK_POSTPTR(b), Memento_PostSize); | |
| 1517 if (type == 0) { /* malloc */ | |
| 1518 VALGRIND_MAKE_MEM_UNDEFINED(MEMBLK_TOBLK(b), b->rawsize); | |
| 1519 } else if (type == 1) { /* free */ | |
| 1520 VALGRIND_MAKE_MEM_NOACCESS(MEMBLK_TOBLK(b), b->rawsize); | |
| 1521 } | |
| 1522 VALGRIND_MAKE_MEM_NOACCESS(b, sizeof(Memento_BlkHeader)); | |
| 1523 VALGRIND_MAKE_MEM_NOACCESS(&blks->tail, sizeof(Memento_BlkHeader *)); | |
| 1524 } | |
| 1525 | |
| 1526 typedef struct BlkCheckData { | |
| 1527 /* found holds some bits: | |
| 1528 * Bit 0 (1) -> At least one block has been checked. | |
| 1529 * Bit 1 (2) -> We have found an "Allocated block". | |
| 1530 * Bit 2 (4) -> We have found a "Freed block". | |
| 1531 * Bit 3 (8) -> Trigger a breakpoint on completion. | |
| 1532 */ | |
| 1533 int found; | |
| 1534 int preCorrupt; | |
| 1535 int postCorrupt; | |
| 1536 int freeCorrupt; | |
| 1537 size_t index; | |
| 1538 } BlkCheckData; | |
| 1539 | |
| 1540 #ifndef MEMENTO_LEAKONLY | |
| 1541 static int Memento_Internal_checkAllocedBlock(Memento_BlkHeader *b, void *arg) | |
| 1542 { | |
| 1543 int i; | |
| 1544 MEMENTO_UINT32 *ip; | |
| 1545 unsigned char *p; | |
| 1546 BlkCheckData *data = (BlkCheckData *)arg; | |
| 1547 | |
| 1548 ip = (MEMENTO_UINT32 *)(void *)(b->preblk); | |
| 1549 i = Memento_PreSize>>2; | |
| 1550 do { | |
| 1551 if (*ip++ != MEMENTO_PREFILL_UINT32) | |
| 1552 goto pre_corrupt; | |
| 1553 } while (--i); | |
| 1554 if (0) { | |
| 1555 pre_corrupt: | |
| 1556 data->preCorrupt = 1; | |
| 1557 } | |
| 1558 /* Postfill may not be aligned, so have to be slower */ | |
| 1559 p = MEMBLK_POSTPTR(b); | |
| 1560 i = Memento_PostSize-4; | |
| 1561 if ((intptr_t)p & 1) | |
| 1562 { | |
| 1563 if (*p++ != MEMENTO_POSTFILL) | |
| 1564 goto post_corrupt; | |
| 1565 i--; | |
| 1566 } | |
| 1567 if ((intptr_t)p & 2) | |
| 1568 { | |
| 1569 if (*(MEMENTO_UINT16 *)p != MEMENTO_POSTFILL_UINT16) | |
| 1570 goto post_corrupt; | |
| 1571 p += 2; | |
| 1572 i -= 2; | |
| 1573 } | |
| 1574 do { | |
| 1575 if (*(MEMENTO_UINT32 *)p != MEMENTO_POSTFILL_UINT32) | |
| 1576 goto post_corrupt; | |
| 1577 p += 4; | |
| 1578 i -= 4; | |
| 1579 } while (i >= 0); | |
| 1580 if (i & 2) | |
| 1581 { | |
| 1582 if (*(MEMENTO_UINT16 *)p != MEMENTO_POSTFILL_UINT16) | |
| 1583 goto post_corrupt; | |
| 1584 p += 2; | |
| 1585 } | |
| 1586 if (i & 1) | |
| 1587 { | |
| 1588 if (*p != MEMENTO_POSTFILL) | |
| 1589 goto post_corrupt; | |
| 1590 } | |
| 1591 if (0) { | |
| 1592 post_corrupt: | |
| 1593 data->postCorrupt = 1; | |
| 1594 } | |
| 1595 if ((data->freeCorrupt | data->preCorrupt | data->postCorrupt) == 0) { | |
| 1596 b->lastCheckedOK = memento.sequence; | |
| 1597 } | |
| 1598 data->found |= 1; | |
| 1599 return 0; | |
| 1600 } | |
| 1601 | |
| 1602 static int Memento_Internal_checkFreedBlock(Memento_BlkHeader *b, void *arg) | |
| 1603 { | |
| 1604 size_t i; | |
| 1605 unsigned char *p; | |
| 1606 BlkCheckData *data = (BlkCheckData *)arg; | |
| 1607 | |
| 1608 p = MEMBLK_TOBLK(b); /* p will always be aligned */ | |
| 1609 i = b->rawsize; | |
| 1610 /* Attempt to speed this up by checking an (aligned) int at a time */ | |
| 1611 if (i >= 4) { | |
| 1612 i -= 4; | |
| 1613 do { | |
| 1614 if (*(MEMENTO_UINT32 *)p != MEMENTO_FREEFILL_UINT32) | |
| 1615 goto mismatch4; | |
| 1616 p += 4; | |
| 1617 i -= 4; | |
| 1618 } while (i > 0); | |
| 1619 i += 4; | |
| 1620 } | |
| 1621 if (i & 2) { | |
| 1622 if (*(MEMENTO_UINT16 *)p != MEMENTO_FREEFILL_UINT16) | |
| 1623 goto mismatch; | |
| 1624 p += 2; | |
| 1625 i -= 2; | |
| 1626 } | |
| 1627 if (0) { | |
| 1628 mismatch4: | |
| 1629 i += 4; | |
| 1630 } | |
| 1631 mismatch: | |
| 1632 while (i) { | |
| 1633 if (*p++ != (unsigned char)MEMENTO_FREEFILL) | |
| 1634 break; | |
| 1635 i--; | |
| 1636 } | |
| 1637 if (i) { | |
| 1638 data->freeCorrupt = 1; | |
| 1639 data->index = b->rawsize-i; | |
| 1640 } | |
| 1641 return Memento_Internal_checkAllocedBlock(b, arg); | |
| 1642 } | |
| 1643 #endif /* MEMENTO_LEAKONLY */ | |
| 1644 | |
| 1645 static void Memento_removeBlock(Memento_Blocks *blks, | |
| 1646 Memento_BlkHeader *b) | |
| 1647 { | |
| 1648 Memento_removeBlockSplay(blks, b); | |
| 1649 VALGRIND_MAKE_MEM_DEFINED(b, sizeof(*b)); | |
| 1650 if (b->next) { | |
| 1651 VALGRIND_MAKE_MEM_DEFINED(&b->next->prev, sizeof(b->next->prev)); | |
| 1652 b->next->prev = b->prev; | |
| 1653 VALGRIND_MAKE_MEM_NOACCESS(&b->next->prev, sizeof(b->next->prev)); | |
| 1654 } | |
| 1655 if (b->prev) { | |
| 1656 VALGRIND_MAKE_MEM_DEFINED(&b->prev->next, sizeof(b->prev->next)); | |
| 1657 b->prev->next = b->next; | |
| 1658 VALGRIND_MAKE_MEM_NOACCESS(&b->prev->next, sizeof(b->prev->next)); | |
| 1659 } | |
| 1660 if (blks->tail == b) | |
| 1661 blks->tail = b->prev; | |
| 1662 if (blks->head == b) | |
| 1663 blks->head = b->next; | |
| 1664 VALGRIND_MAKE_MEM_NOACCESS(b, sizeof(*b)); | |
| 1665 } | |
| 1666 | |
| 1667 static void free_block(Memento_BlkHeader *head) | |
| 1668 { | |
| 1669 #ifdef MEMENTO_DETAILS | |
| 1670 Memento_BlkDetails *details = head->details; | |
| 1671 | |
| 1672 while (details) | |
| 1673 { | |
| 1674 Memento_BlkDetails *next = details->next; | |
| 1675 MEMENTO_UNDERLYING_FREE(details); | |
| 1676 details = next; | |
| 1677 } | |
| 1678 #endif | |
| 1679 MEMENTO_UNDERLYING_FREE(head); | |
| 1680 } | |
| 1681 | |
| 1682 static int Memento_Internal_makeSpace(size_t space) | |
| 1683 { | |
| 1684 /* If too big, it can never go on the freelist */ | |
| 1685 if (space > MEMENTO_FREELIST_MAX_SINGLE_BLOCK) | |
| 1686 return 0; | |
| 1687 /* Pretend we added it on. */ | |
| 1688 memento.freeListSize += space; | |
| 1689 /* Ditch blocks until it fits within our limit */ | |
| 1690 while (memento.freeListSize > MEMENTO_FREELIST_MAX) { | |
| 1691 Memento_BlkHeader *head = memento.free.head; | |
| 1692 VALGRIND_MAKE_MEM_DEFINED(head, sizeof(*head)); | |
| 1693 memento.free.head = head->next; | |
| 1694 memento.freeListSize -= MEMBLK_SIZE(head->rawsize); | |
| 1695 Memento_removeBlockSplay(&memento.free, head); | |
| 1696 VALGRIND_MAKE_MEM_DEFINED(head, sizeof(*head)); | |
| 1697 free_block(head); | |
| 1698 } | |
| 1699 /* Make sure we haven't just completely emptied the free list */ | |
| 1700 /* (This should never happen, but belt and braces... */ | |
| 1701 if (memento.free.head == NULL) | |
| 1702 memento.free.tail = NULL; | |
| 1703 return 1; | |
| 1704 } | |
| 1705 | |
| 1706 static int Memento_appBlocks(Memento_Blocks *blks, | |
| 1707 int (*app)(Memento_BlkHeader *, | |
| 1708 void *), | |
| 1709 void *arg) | |
| 1710 { | |
| 1711 Memento_BlkHeader *head = blks->head; | |
| 1712 Memento_BlkHeader *next; | |
| 1713 int result; | |
| 1714 while (head) { | |
| 1715 VALGRIND_MAKE_MEM_DEFINED(head, sizeof(Memento_BlkHeader)); | |
| 1716 VALGRIND_MAKE_MEM_DEFINED(MEMBLK_TOBLK(head), | |
| 1717 head->rawsize + Memento_PostSize); | |
| 1718 result = app(head, arg); | |
| 1719 next = head->next; | |
| 1720 VALGRIND_MAKE_MEM_NOACCESS(MEMBLK_POSTPTR(head), Memento_PostSize); | |
| 1721 VALGRIND_MAKE_MEM_NOACCESS(head, sizeof(Memento_BlkHeader)); | |
| 1722 if (result) | |
| 1723 return result; | |
| 1724 head = next; | |
| 1725 } | |
| 1726 return 0; | |
| 1727 } | |
| 1728 | |
| 1729 static Memento_BlkHeader * | |
| 1730 find_enclosing_block(Memento_Blocks *blks, | |
| 1731 void *addr, | |
| 1732 int *flags) | |
| 1733 { | |
| 1734 Memento_BlkHeader *blk; | |
| 1735 | |
| 1736 VALGRIND_MAKE_MEM_DEFINED(&blks->top, sizeof(blks->top)); | |
| 1737 blk = blks->top; | |
| 1738 while (blk) | |
| 1739 { | |
| 1740 Memento_BlkHeader *oblk = blk; | |
| 1741 char *blkstart; | |
| 1742 char *blkend; | |
| 1743 VALGRIND_MAKE_MEM_DEFINED(blk, sizeof(Memento_BlkHeader)); | |
| 1744 if (addr < (void *)oblk) { | |
| 1745 blk = blk->left; | |
| 1746 VALGRIND_MAKE_MEM_UNDEFINED(oblk, sizeof(Memento_BlkHeader)); | |
| 1747 continue; | |
| 1748 } | |
| 1749 blkstart = (char *)MEMBLK_TOBLK(blk); | |
| 1750 blkend = &blkstart[blk->rawsize]; | |
| 1751 if (addr >= (void *)(blkend + Memento_PostSize)) { | |
| 1752 blk = blk->right; | |
| 1753 VALGRIND_MAKE_MEM_UNDEFINED(oblk, sizeof(Memento_BlkHeader)); | |
| 1754 continue; | |
| 1755 } | |
| 1756 if (flags) { | |
| 1757 if (((void *)blkstart <= addr) && (addr < (void *)blkend)) | |
| 1758 *flags = 1; | |
| 1759 else if (((void *)blk <= addr) && (addr < (void *)blkstart)) | |
| 1760 *flags = 2; | |
| 1761 else | |
| 1762 *flags = 3; | |
| 1763 } | |
| 1764 VALGRIND_MAKE_MEM_UNDEFINED(oblk, sizeof(Memento_BlkHeader)); | |
| 1765 return blk; | |
| 1766 } | |
| 1767 return NULL; | |
| 1768 } | |
| 1769 | |
| 1770 #ifndef MEMENTO_LEAKONLY | |
| 1771 /* Distrustful - check the block is a real one */ | |
| 1772 static int Memento_appBlockUser(Memento_Blocks *blks, | |
| 1773 int (*app)(Memento_BlkHeader *, | |
| 1774 void *), | |
| 1775 void *arg, | |
| 1776 Memento_BlkHeader *b) | |
| 1777 { | |
| 1778 int result; | |
| 1779 Memento_BlkHeader *head = find_enclosing_block(blks, b, NULL); | |
| 1780 if (head == NULL) | |
| 1781 return 0; | |
| 1782 | |
| 1783 VALGRIND_MAKE_MEM_DEFINED(head, sizeof(Memento_BlkHeader)); | |
| 1784 VALGRIND_MAKE_MEM_DEFINED(MEMBLK_TOBLK(head), | |
| 1785 head->rawsize + Memento_PostSize); | |
| 1786 result = app(head, arg); | |
| 1787 VALGRIND_MAKE_MEM_NOACCESS(MEMBLK_POSTPTR(head), Memento_PostSize); | |
| 1788 VALGRIND_MAKE_MEM_NOACCESS(head, sizeof(Memento_BlkHeader)); | |
| 1789 return result; | |
| 1790 } | |
| 1791 | |
| 1792 static int Memento_appBlock(Memento_Blocks *blks, | |
| 1793 int (*app)(Memento_BlkHeader *, | |
| 1794 void *), | |
| 1795 void *arg, | |
| 1796 Memento_BlkHeader *b) | |
| 1797 { | |
| 1798 int result; | |
| 1799 (void)blks; | |
| 1800 VALGRIND_MAKE_MEM_DEFINED(b, sizeof(Memento_BlkHeader)); | |
| 1801 VALGRIND_MAKE_MEM_DEFINED(MEMBLK_TOBLK(b), | |
| 1802 b->rawsize + Memento_PostSize); | |
| 1803 result = app(b, arg); | |
| 1804 VALGRIND_MAKE_MEM_NOACCESS(MEMBLK_POSTPTR(b), Memento_PostSize); | |
| 1805 VALGRIND_MAKE_MEM_NOACCESS(b, sizeof(Memento_BlkHeader)); | |
| 1806 return result; | |
| 1807 } | |
| 1808 #endif /* MEMENTO_LEAKONLY */ | |
| 1809 | |
| 1810 static int showBlock(Memento_BlkHeader *b, int space) | |
| 1811 { | |
| 1812 int seq; | |
| 1813 VALGRIND_MAKE_MEM_DEFINED(b, sizeof(Memento_BlkHeader)); | |
| 1814 fprintf(stderr, FMTP":(size=" FMTZ ",num=%d)", | |
| 1815 MEMBLK_TOBLK(b), (FMTZ_CAST)b->rawsize, b->sequence); | |
| 1816 if (b->label) | |
| 1817 fprintf(stderr, "%c(%s)", space, b->label); | |
| 1818 if (b->flags & Memento_Flag_KnownLeak) | |
| 1819 fprintf(stderr, "(Known Leak)"); | |
| 1820 seq = b->sequence; | |
| 1821 VALGRIND_MAKE_MEM_NOACCESS(b, sizeof(Memento_BlkHeader)); | |
| 1822 return seq; | |
| 1823 } | |
| 1824 | |
| 1825 static void blockDisplay(Memento_BlkHeader *b, int n) | |
| 1826 { | |
| 1827 n++; | |
| 1828 while (n > 40) | |
| 1829 { | |
| 1830 fprintf(stderr, "*"); | |
| 1831 n -= 40; | |
| 1832 } | |
| 1833 while(n > 0) | |
| 1834 { | |
| 1835 int i = n; | |
| 1836 if (i > 32) | |
| 1837 i = 32; | |
| 1838 n -= i; | |
| 1839 fprintf(stderr, "%s", &" "[32-i]); | |
| 1840 } | |
| 1841 showBlock(b, '\t'); | |
| 1842 fprintf(stderr, "\n"); | |
| 1843 } | |
| 1844 | |
| 1845 static int Memento_listBlock(Memento_BlkHeader *b, | |
| 1846 void *arg) | |
| 1847 { | |
| 1848 size_t *counts = (size_t *)arg; | |
| 1849 blockDisplay(b, 0); | |
| 1850 counts[0]++; | |
| 1851 VALGRIND_MAKE_MEM_DEFINED(b, sizeof(Memento_BlkHeader)); | |
| 1852 counts[1]+= b->rawsize; | |
| 1853 VALGRIND_MAKE_MEM_NOACCESS(b, sizeof(Memento_BlkHeader)); | |
| 1854 return 0; | |
| 1855 } | |
| 1856 | |
| 1857 static void doNestedDisplay(Memento_BlkHeader *b, | |
| 1858 int depth, | |
| 1859 int include_known_leaks | |
| 1860 ) | |
| 1861 { | |
| 1862 /* Try and avoid recursion if we can help it */ | |
| 1863 do { | |
| 1864 Memento_BlkHeader *c = NULL; | |
| 1865 if (!include_known_leaks && (b->flags & Memento_Flag_KnownLeak)) | |
| 1866 ; | |
| 1867 else | |
| 1868 blockDisplay(b, depth); | |
| 1869 VALGRIND_MAKE_MEM_DEFINED(b, sizeof(Memento_BlkHeader)); | |
| 1870 if (b->sibling) { | |
| 1871 c = b->child; | |
| 1872 b = b->sibling; | |
| 1873 } else { | |
| 1874 b = b->child; | |
| 1875 depth++; | |
| 1876 } | |
| 1877 VALGRIND_MAKE_MEM_NOACCESS(b, sizeof(Memento_BlkHeader)); | |
| 1878 if (c) | |
| 1879 doNestedDisplay(c, depth+1, include_known_leaks); | |
| 1880 } while (b); | |
| 1881 } | |
| 1882 | |
| 1883 static int ptrcmp(const void *a_, const void *b_) | |
| 1884 { | |
| 1885 const char **a = (const char **)a_; | |
| 1886 const char **b = (const char **)b_; | |
| 1887 return (int)(*a-*b); | |
| 1888 } | |
| 1889 | |
| 1890 static | |
| 1891 int Memento_listBlocksNested(int include_known_leaks) | |
| 1892 { | |
| 1893 int count, i, count_excluding_known_leaks, count_known_leaks; | |
| 1894 size_t size; | |
| 1895 size_t size_excluding_known_leaks, size_known_leaks; | |
| 1896 Memento_BlkHeader *b, *prev; | |
| 1897 void **blocks, *minptr, *maxptr; | |
| 1898 intptr_t mask; | |
| 1899 | |
| 1900 /* Count the blocks */ | |
| 1901 count = 0; | |
| 1902 size = 0; | |
| 1903 count_excluding_known_leaks = 0; | |
| 1904 size_excluding_known_leaks = 0; | |
| 1905 count_known_leaks = 0; | |
| 1906 size_known_leaks = 0; | |
| 1907 for (b = memento.used.head; b; b = b->next) { | |
| 1908 VALGRIND_MAKE_MEM_DEFINED(b, sizeof(*b)); | |
| 1909 count++; | |
| 1910 size += b->rawsize; | |
| 1911 if (b->flags & Memento_Flag_KnownLeak) { | |
| 1912 count_known_leaks += 1; | |
| 1913 size_known_leaks += b->rawsize; | |
| 1914 } | |
| 1915 else { | |
| 1916 count_excluding_known_leaks += 1; | |
| 1917 size_excluding_known_leaks += b->rawsize; | |
| 1918 } | |
| 1919 } | |
| 1920 | |
| 1921 if (memento.showDetailedBlocks) | |
| 1922 { | |
| 1923 /* Make our block list */ | |
| 1924 blocks = MEMENTO_UNDERLYING_MALLOC(sizeof(void *) * count); | |
| 1925 if (blocks == NULL) | |
| 1926 return 1; | |
| 1927 | |
| 1928 /* Populate our block list */ | |
| 1929 b = memento.used.head; | |
| 1930 minptr = maxptr = MEMBLK_TOBLK(b); | |
| 1931 mask = (intptr_t)minptr; | |
| 1932 for (i = 0; b; b = b->next, i++) { | |
| 1933 void *p = MEMBLK_TOBLK(b); | |
| 1934 mask &= (intptr_t)p; | |
| 1935 if (p < minptr) | |
| 1936 minptr = p; | |
| 1937 if (p > maxptr) | |
| 1938 maxptr = p; | |
| 1939 blocks[i] = p; | |
| 1940 b->flags &= ~Memento_Flag_HasParent; | |
| 1941 b->child = NULL; | |
| 1942 b->sibling = NULL; | |
| 1943 b->prev = NULL; /* parent */ | |
| 1944 } | |
| 1945 qsort(blocks, count, sizeof(void *), ptrcmp); | |
| 1946 | |
| 1947 /* Now, calculate tree */ | |
| 1948 for (b = memento.used.head; b; b = b->next) { | |
| 1949 char *p = MEMBLK_TOBLK(b); | |
| 1950 size_t end = (b->rawsize < MEMENTO_PTRSEARCH ? b->rawsize : MEMENTO_PTRSEARCH); | |
| 1951 size_t z; | |
| 1952 VALGRIND_MAKE_MEM_DEFINED(p, end); | |
| 1953 if (end > sizeof(void *)-1) | |
| 1954 end -= sizeof(void *)-1; | |
| 1955 else | |
| 1956 end = 0; | |
| 1957 for (z = MEMENTO_SEARCH_SKIP; z < end; z += sizeof(void *)) { | |
| 1958 void *q = *(void **)(&p[z]); | |
| 1959 void **r; | |
| 1960 | |
| 1961 /* Do trivial checks on pointer */ | |
| 1962 if ((mask & (intptr_t)q) != mask || q < minptr || q > maxptr) | |
| 1963 continue; | |
| 1964 | |
| 1965 /* Search for pointer */ | |
| 1966 r = bsearch(&q, blocks, count, sizeof(void *), ptrcmp); | |
| 1967 if (r) { | |
| 1968 /* Found child */ | |
| 1969 Memento_BlkHeader *child = MEMBLK_FROMBLK(*r); | |
| 1970 Memento_BlkHeader *parent; | |
| 1971 | |
| 1972 /* We're assuming tree structure, not graph - ignore second | |
| 1973 * and subsequent pointers. */ | |
| 1974 if (child->prev != NULL) /* parent */ | |
| 1975 continue; | |
| 1976 if (child->flags & Memento_Flag_HasParent) | |
| 1977 continue; | |
| 1978 | |
| 1979 /* Not interested in pointers to ourself! */ | |
| 1980 if (child == b) | |
| 1981 continue; | |
| 1982 | |
| 1983 /* We're also assuming acyclicness here. If this is one of | |
| 1984 * our parents, ignore it. */ | |
| 1985 parent = b->prev; /* parent */ | |
| 1986 while (parent != NULL && parent != child) | |
| 1987 parent = parent->prev; /* parent */ | |
| 1988 if (parent == child) | |
| 1989 continue; | |
| 1990 | |
| 1991 child->sibling = b->child; | |
| 1992 b->child = child; | |
| 1993 child->prev = b; /* parent */ | |
| 1994 child->flags |= Memento_Flag_HasParent; | |
| 1995 } | |
| 1996 } | |
| 1997 } | |
| 1998 | |
| 1999 /* Now display with nesting */ | |
| 2000 for (b = memento.used.head; b; b = b->next) { | |
| 2001 if ((b->flags & Memento_Flag_HasParent) == 0) | |
| 2002 doNestedDisplay(b, 0, include_known_leaks); | |
| 2003 } | |
| 2004 | |
| 2005 MEMENTO_UNDERLYING_FREE(blocks); | |
| 2006 | |
| 2007 /* Now put the blocks back for valgrind, and restore the prev | |
| 2008 * and magic values. */ | |
| 2009 prev = NULL; | |
| 2010 for (b = memento.used.head; b;) { | |
| 2011 Memento_BlkHeader *next = b->next; | |
| 2012 b->prev = prev; | |
| 2013 b->child = MEMENTO_CHILD_MAGIC; | |
| 2014 b->sibling = MEMENTO_SIBLING_MAGIC; | |
| 2015 prev = b; | |
| 2016 VALGRIND_MAKE_MEM_NOACCESS(b, sizeof(*b)); | |
| 2017 b = next; | |
| 2018 } | |
| 2019 } | |
| 2020 | |
| 2021 fprintf(stderr, " Total number of blocks = %d\n", count); | |
| 2022 fprintf(stderr, " Total size of blocks = "FMTZ"\n", (FMTZ_CAST)size); | |
| 2023 if (!include_known_leaks) { | |
| 2024 fprintf(stderr, " Excluding known leaks:\n"); | |
| 2025 fprintf(stderr, " Number of blocks = %d\n", count_excluding_known_leaks); | |
| 2026 fprintf(stderr, " Size of blocks = "FMTZ"\n", (FMTZ_CAST) size_excluding_known_leaks); | |
| 2027 fprintf(stderr, " Known leaks:\n"); | |
| 2028 fprintf(stderr, " Number of blocks = %d\n", count_known_leaks); | |
| 2029 fprintf(stderr, " Size of blocks = "FMTZ"\n", (FMTZ_CAST) size_known_leaks); | |
| 2030 } | |
| 2031 | |
| 2032 return 0; | |
| 2033 } | |
| 2034 | |
| 2035 static void Memento_listBlocksInternal(int include_known_leaks) | |
| 2036 { | |
| 2037 MEMENTO_LOCK(); | |
| 2038 if (include_known_leaks) | |
| 2039 fprintf(stderr, "Allocated blocks:\n"); | |
| 2040 else | |
| 2041 fprintf(stderr, "Allocated blocks (excluding known leaks):\n"); | |
| 2042 if (Memento_listBlocksNested(include_known_leaks)) | |
| 2043 { | |
| 2044 size_t counts[2]; | |
| 2045 counts[0] = 0; | |
| 2046 counts[1] = 0; | |
| 2047 Memento_appBlocks(&memento.used, Memento_listBlock, &counts[0]); | |
| 2048 fprintf(stderr, " Total number of blocks = "FMTZ"\n", (FMTZ_CAST)counts[0]); | |
| 2049 fprintf(stderr, " Total size of blocks = "FMTZ"\n", (FMTZ_CAST)counts[1]); | |
| 2050 } | |
| 2051 MEMENTO_UNLOCK(); | |
| 2052 } | |
| 2053 | |
| 2054 void Memento_listBlocks() | |
| 2055 { | |
| 2056 Memento_listBlocksInternal(1 /*include_known_leaks*/); | |
| 2057 } | |
| 2058 | |
| 2059 void Memento_listLargeBlocks() | |
| 2060 { | |
| 2061 Memento_BlkHeader *b; | |
| 2062 #define LARGE_BLOCKS 100 | |
| 2063 Memento_BlkHeader *blocks[LARGE_BLOCKS]; | |
| 2064 int i, n = 0; | |
| 2065 | |
| 2066 MEMENTO_LOCK(); | |
| 2067 | |
| 2068 for (b = memento.used.head; b; b = b->next) { | |
| 2069 size_t size = b->rawsize; | |
| 2070 if (n < LARGE_BLOCKS || size > blocks[n - 1]->rawsize) | |
| 2071 { | |
| 2072 /* We need to insert this block into our list. */ | |
| 2073 int l = 0, r = n; | |
| 2074 while (l < r) | |
| 2075 { | |
| 2076 int m = (l + r) >> 1; | |
| 2077 if (size > blocks[m]->rawsize) | |
| 2078 r = m; | |
| 2079 else if (blocks[m]->rawsize > size) | |
| 2080 l = m+1; | |
| 2081 else | |
| 2082 l = r = m+1; | |
| 2083 } | |
| 2084 if (n < LARGE_BLOCKS) | |
| 2085 n++; | |
| 2086 if (l < n-1) | |
| 2087 memmove(&blocks[l+1], &blocks[l], sizeof(void *) * (n - l - 1)); | |
| 2088 if (l < LARGE_BLOCKS) | |
| 2089 blocks[l] = b; | |
| 2090 } | |
| 2091 } | |
| 2092 | |
| 2093 for (i = 0; i < n; i++) | |
| 2094 blockDisplay(blocks[i], 0); | |
| 2095 | |
| 2096 MEMENTO_UNLOCK(); | |
| 2097 } | |
| 2098 | |
| 2099 static int Memento_listNewBlock(Memento_BlkHeader *b, | |
| 2100 void *arg) | |
| 2101 { | |
| 2102 if (b->flags & Memento_Flag_OldBlock) | |
| 2103 return 0; | |
| 2104 b->flags |= Memento_Flag_OldBlock; | |
| 2105 return Memento_listBlock(b, arg); | |
| 2106 } | |
| 2107 | |
| 2108 void Memento_listNewBlocks(void) | |
| 2109 { | |
| 2110 size_t counts[2]; | |
| 2111 MEMENTO_LOCK(); | |
| 2112 counts[0] = 0; | |
| 2113 counts[1] = 0; | |
| 2114 fprintf(stderr, "Blocks allocated and still extant since last list:\n"); | |
| 2115 Memento_appBlocks(&memento.used, Memento_listNewBlock, &counts[0]); | |
| 2116 fprintf(stderr, " Total number of blocks = "FMTZ"\n", (FMTZ_CAST)counts[0]); | |
| 2117 fprintf(stderr, " Total size of blocks = "FMTZ"\n", (FMTZ_CAST)counts[1]); | |
| 2118 MEMENTO_UNLOCK(); | |
| 2119 } | |
| 2120 | |
| 2121 typedef struct | |
| 2122 { | |
| 2123 size_t counts[2]; | |
| 2124 unsigned int phase; | |
| 2125 } phased_t; | |
| 2126 | |
| 2127 static int Memento_listPhasedBlock(Memento_BlkHeader *b, | |
| 2128 void *arg) | |
| 2129 { | |
| 2130 phased_t *phase = (phased_t *)arg; | |
| 2131 if ((b->flags & phase->phase) == 0) | |
| 2132 return 0; | |
| 2133 b->flags = (b->flags & ~Memento_Flag_PhaseMask) | ((b->flags >> 1) & Memento_Flag_PhaseMask); | |
| 2134 return Memento_listBlock(b, arg); | |
| 2135 } | |
| 2136 | |
| 2137 static int Memento_listNewPhasedBlock(Memento_BlkHeader *b, | |
| 2138 void *arg) | |
| 2139 { | |
| 2140 if ((b->flags & Memento_Flag_PhaseMask) != 0) | |
| 2141 return 0; | |
| 2142 b->flags |= Memento_Flag_LastPhase; | |
| 2143 return Memento_listBlock(b, arg); | |
| 2144 } | |
| 2145 | |
| 2146 static int Memento_startPhasing(Memento_BlkHeader *b, | |
| 2147 void *arg) | |
| 2148 { | |
| 2149 b->flags |= *(int *)arg; | |
| 2150 return 0; | |
| 2151 } | |
| 2152 | |
| 2153 /* On the first call to this, we mark all blocks with the | |
| 2154 * lowest 'phase' bit, (call this phase m) so they will | |
| 2155 * never be reported. | |
| 2156 * | |
| 2157 * On subsequent calls, we: | |
| 2158 * for (n = m-1; n > 0; n--) | |
| 2159 * report all blocks in phase n, moving them to n+1. | |
| 2160 * report all new blocks, and place them in phase 0. | |
| 2161 * | |
| 2162 * The upshot of this is that if you call Memento_listPhasedBlocks() | |
| 2163 * at a given point in the code, then you can watch for how long blocks | |
| 2164 * live between each time the code reaches that point. | |
| 2165 * | |
| 2166 * This is basically like Memento_listNewBlocks(), but allows for | |
| 2167 * the fact that sometimes blocks are freed just after the call. | |
| 2168 */ | |
| 2169 void Memento_listPhasedBlocks(void) | |
| 2170 { | |
| 2171 phased_t phase; | |
| 2172 int num = 0; | |
| 2173 MEMENTO_LOCK(); | |
| 2174 phase.phase = Memento_Flag_LastPhase; | |
| 2175 while ((phase.phase>>1) & Memento_Flag_PhaseMask) | |
| 2176 num++, phase.phase >>= 1; | |
| 2177 if (memento.phasing == 0) | |
| 2178 { | |
| 2179 fprintf(stderr, "Commencing Phasing:\n"); | |
| 2180 memento.phasing = 1; | |
| 2181 Memento_appBlocks(&memento.used, Memento_startPhasing, &phase.phase); | |
| 2182 } else { | |
| 2183 phase.phase <<= 1; | |
| 2184 do | |
| 2185 { | |
| 2186 phase.counts[0] = 0; | |
| 2187 phase.counts[1] = 0; | |
| 2188 fprintf(stderr, "Blocks allocated and still extant: In phase %d (%x):\n", num, phase.phase); | |
| 2189 Memento_appBlocks(&memento.used, Memento_listPhasedBlock, &phase); | |
| 2190 fprintf(stderr, " Total number of blocks = "FMTZ"\n", (FMTZ_CAST)phase.counts[0]); | |
| 2191 fprintf(stderr, " Total size of blocks = "FMTZ"\n", (FMTZ_CAST)phase.counts[1]); | |
| 2192 phase.phase = phase.phase<<1; | |
| 2193 num--; | |
| 2194 } | |
| 2195 while (phase.phase != 0); | |
| 2196 phase.counts[0] = 0; | |
| 2197 phase.counts[1] = 0; | |
| 2198 fprintf(stderr, "Blocks allocated and still extant: In phase 0:\n"); | |
| 2199 Memento_appBlocks(&memento.used, Memento_listNewPhasedBlock, &phase); | |
| 2200 fprintf(stderr, " Total number of blocks = "FMTZ"\n", (FMTZ_CAST)phase.counts[0]); | |
| 2201 fprintf(stderr, " Total size of blocks = "FMTZ"\n", (FMTZ_CAST)phase.counts[1]); | |
| 2202 } | |
| 2203 MEMENTO_UNLOCK(); | |
| 2204 } | |
| 2205 | |
| 2206 static void Memento_endStats(void) | |
| 2207 { | |
| 2208 fprintf(stderr, "Total memory malloced = "FMTZ" bytes\n", (FMTZ_CAST)memento.totalAlloc); | |
| 2209 fprintf(stderr, "Peak memory malloced = "FMTZ" bytes\n", (FMTZ_CAST)memento.peakAlloc); | |
| 2210 fprintf(stderr, FMTZ" mallocs, "FMTZ" frees, "FMTZ" reallocs\n", (FMTZ_CAST)memento.numMallocs, | |
| 2211 (FMTZ_CAST)memento.numFrees, (FMTZ_CAST)memento.numReallocs); | |
| 2212 fprintf(stderr, "Average allocation size "FMTZ" bytes\n", (FMTZ_CAST) | |
| 2213 (memento.numMallocs != 0 ? memento.totalAlloc/memento.numMallocs: 0)); | |
| 2214 #ifdef MEMENTO_DETAILS | |
| 2215 if (memento.hashCollisions) | |
| 2216 fprintf(stderr, "%d hash collisions\n", memento.hashCollisions); | |
| 2217 #endif | |
| 2218 } | |
| 2219 | |
| 2220 void Memento_stats(void) | |
| 2221 { | |
| 2222 MEMENTO_LOCK(); | |
| 2223 fprintf(stderr, "Current memory malloced = "FMTZ" bytes\n", (FMTZ_CAST)memento.alloc); | |
| 2224 Memento_endStats(); | |
| 2225 MEMENTO_UNLOCK(); | |
| 2226 } | |
| 2227 | |
| 2228 #ifdef MEMENTO_DETAILS | |
| 2229 static int showInfo(Memento_BlkHeader *b, void *arg) | |
| 2230 { | |
| 2231 Memento_BlkDetails *details; | |
| 2232 | |
| 2233 int include_known_leaks = (arg) ? *(int*) arg : 1; | |
| 2234 | |
| 2235 fprintf(stderr, FMTP":(size="FMTZ",num=%d)", | |
| 2236 MEMBLK_TOBLK(b), (FMTZ_CAST)b->rawsize, b->sequence); | |
| 2237 if (b->label) | |
| 2238 fprintf(stderr, " (%s)", b->label); | |
| 2239 if (b->flags & Memento_Flag_KnownLeak) | |
| 2240 fprintf(stderr, "(Known Leak)"); | |
| 2241 fprintf(stderr, "\nEvents:\n"); | |
| 2242 | |
| 2243 for (details = b->details; details; details = details->next) | |
| 2244 { | |
| 2245 if (memento.hideMultipleReallocs && | |
| 2246 details->type == Memento_EventType_realloc && | |
| 2247 details->next && | |
| 2248 details->next->type == Memento_EventType_realloc) { | |
| 2249 continue; | |
| 2250 } | |
| 2251 fprintf(stderr, " Event %d (%s)\n", details->sequence, eventType[(int)details->type]); | |
| 2252 if (memento.hideRefChangeBacktraces && ( | |
| 2253 details->type == Memento_EventType_takeRef | |
| 2254 || details->type == Memento_EventType_dropRef)) | |
| 2255 continue; | |
| 2256 if (!include_known_leaks && (b->flags & Memento_Flag_KnownLeak)) | |
| 2257 continue; | |
| 2258 Memento_showHashedStacktrace(details->trace); | |
| 2259 if (memento.showDetailedBlocks > 0) { | |
| 2260 memento.showDetailedBlocks -= 1; | |
| 2261 if (memento.showDetailedBlocks == 0) { | |
| 2262 fprintf(stderr, "Stopping display of block details because memento.showDetailedBlocks is now zero.\n"); | |
| 2263 return 1; | |
| 2264 } | |
| 2265 } | |
| 2266 } | |
| 2267 return 0; | |
| 2268 } | |
| 2269 #endif | |
| 2270 | |
| 2271 static void Memento_listBlockInfoInternal(int include_known_leaks) | |
| 2272 { | |
| 2273 #ifdef MEMENTO_DETAILS | |
| 2274 MEMENTO_LOCK(); | |
| 2275 fprintf(stderr, "Details of allocated blocks:\n"); | |
| 2276 Memento_appBlocks(&memento.used, showInfo, &include_known_leaks); | |
| 2277 MEMENTO_UNLOCK(); | |
| 2278 #endif | |
| 2279 } | |
| 2280 | |
| 2281 void Memento_listBlockInfo(void) | |
| 2282 { | |
| 2283 Memento_listBlockInfoInternal(1 /*include_known_leaks*/); | |
| 2284 } | |
| 2285 | |
| 2286 void Memento_blockInfo(void *p) | |
| 2287 { | |
| 2288 #ifdef MEMENTO_DETAILS | |
| 2289 Memento_BlkHeader *blk; | |
| 2290 MEMENTO_LOCK(); | |
| 2291 blk = find_enclosing_block(&memento.used, p, NULL); | |
| 2292 if (blk == NULL) | |
| 2293 blk = find_enclosing_block(&memento.free, p, NULL); | |
| 2294 if (blk) | |
| 2295 showInfo(blk, NULL); | |
| 2296 MEMENTO_UNLOCK(); | |
| 2297 #endif | |
| 2298 } | |
| 2299 | |
| 2300 static int Memento_nonLeakBlocksLeaked(void) | |
| 2301 { | |
| 2302 Memento_BlkHeader *blk = memento.used.head; | |
| 2303 while (blk) | |
| 2304 { | |
| 2305 Memento_BlkHeader *next; | |
| 2306 int leaked; | |
| 2307 VALGRIND_MAKE_MEM_DEFINED(blk, sizeof(*blk)); | |
| 2308 leaked = ((blk->flags & Memento_Flag_KnownLeak) == 0); | |
| 2309 next = blk->next; | |
| 2310 VALGRIND_MAKE_MEM_DEFINED(blk, sizeof(*blk)); | |
| 2311 if (leaked) | |
| 2312 return 1; | |
| 2313 blk = next; | |
| 2314 } | |
| 2315 return 0; | |
| 2316 } | |
| 2317 | |
| 2318 void Memento_fin(void) | |
| 2319 { | |
| 2320 int leaked = 0; | |
| 2321 Memento_checkAllMemory(); | |
| 2322 if (!memento.segv) | |
| 2323 { | |
| 2324 Memento_endStats(); | |
| 2325 if (Memento_nonLeakBlocksLeaked()) { | |
| 2326 Memento_listBlocksInternal(0 /*include_known_leaks*/); | |
| 2327 #ifdef MEMENTO_DETAILS | |
| 2328 fprintf(stderr, "\n"); | |
| 2329 if (memento.showDetailedBlocks) | |
| 2330 Memento_listBlockInfoInternal(0 /*include_known_leaks*/); | |
| 2331 #endif | |
| 2332 Memento_breakpoint(); | |
| 2333 leaked = 1; | |
| 2334 } | |
| 2335 } | |
| 2336 if (memento.squeezing) { | |
| 2337 if (memento.pattern == 0) | |
| 2338 fprintf(stderr, "Memory squeezing @ %d complete%s\n", memento.squeezeAt, memento.segv ? " (with SEGV)" : (leaked ? " (with leaks)" : "")); | |
| 2339 else | |
| 2340 fprintf(stderr, "Memory squeezing @ %d (%d) complete%s\n", memento.squeezeAt, memento.pattern, memento.segv ? " (with SEGV)" : (leaked ? " (with leaks)" : "")); | |
| 2341 } else if (memento.segv) { | |
| 2342 fprintf(stderr, "Memento completed (with SEGV)\n"); | |
| 2343 } | |
| 2344 if (memento.failing) | |
| 2345 { | |
| 2346 fprintf(stderr, "MEMENTO_FAILAT=%d\n", memento.failAt); | |
| 2347 fprintf(stderr, "MEMENTO_PATTERN=%d\n", memento.pattern); | |
| 2348 } | |
| 2349 if (memento.nextFailAt != 0) | |
| 2350 { | |
| 2351 fprintf(stderr, "MEMENTO_NEXTFAILAT=%d\n", memento.nextFailAt); | |
| 2352 fprintf(stderr, "MEMENTO_NEXTPATTERN=%d\n", memento.nextPattern); | |
| 2353 } | |
| 2354 if (Memento_nonLeakBlocksLeaked() && memento.abortOnLeak) { | |
| 2355 fprintf(stderr, "Calling abort() because blocks were leaked and MEMENTO_ABORT_ON_LEAK is set.\n"); | |
| 2356 abort(); | |
| 2357 } | |
| 2358 } | |
| 2359 | |
| 2360 /* Reads number from <text> using strtol(). | |
| 2361 * | |
| 2362 * Params: | |
| 2363 * text: | |
| 2364 * text to read. | |
| 2365 * out: | |
| 2366 * pointer to output value. | |
| 2367 * relative: | |
| 2368 * *relative set to 1 if <text> starts with '+' or '-', else set to 0. | |
| 2369 * end: | |
| 2370 * *end is set to point to next unread character after number. | |
| 2371 * | |
| 2372 * Returns 0 on success, else -1. | |
| 2373 */ | |
| 2374 static int read_number(const char *text, int *out, int *relative, char **end) | |
| 2375 { | |
| 2376 if (text[0] == '+' || text[0] == '-') | |
| 2377 *relative = 1; | |
| 2378 else | |
| 2379 *relative = 0; | |
| 2380 errno = 0; | |
| 2381 *out = (int)strtol(text, end, 0 /*base*/); | |
| 2382 if (errno || *end == text) | |
| 2383 { | |
| 2384 fprintf(stderr, "Failed to parse number at start of '%s'.\n", text); | |
| 2385 return -1; | |
| 2386 } | |
| 2387 if (0) | |
| 2388 fprintf(stderr, "text='%s': *out=%i *relative=%i\n", | |
| 2389 text, *out, *relative); | |
| 2390 return 0; | |
| 2391 } | |
| 2392 | |
| 2393 /* Reads number plus optional delta value from <text>. | |
| 2394 * | |
| 2395 * Evaluates <number> or <number>[+|-<delta>]. E.g. text='1234+2' sets *out=1236, | |
| 2396 * text='1234-1' sets *out=1233. | |
| 2397 * | |
| 2398 * Params: | |
| 2399 * text: | |
| 2400 * text to read. | |
| 2401 * out: | |
| 2402 * pointer to output value. | |
| 2403 * end: | |
| 2404 * *end is set to point to next unread character after number. | |
| 2405 * | |
| 2406 * Returns 0 on success, else -1. | |
| 2407 */ | |
| 2408 static int read_number_delta(const char *text, int *out, char **end) | |
| 2409 { | |
| 2410 int e; | |
| 2411 int relative; | |
| 2412 | |
| 2413 e = read_number(text, out, &relative, end); | |
| 2414 if (e) | |
| 2415 return e; | |
| 2416 if (relative) { | |
| 2417 fprintf(stderr, "Base number should not start with '+' or '-' at start of '%s'.\n", | |
| 2418 text); | |
| 2419 return -1; | |
| 2420 } | |
| 2421 if (*end) { | |
| 2422 if (**end == '-' || **end == '+') { | |
| 2423 int delta; | |
| 2424 e = read_number(*end, &delta, &relative, end); | |
| 2425 if (e) | |
| 2426 return e; | |
| 2427 *out += delta; | |
| 2428 } | |
| 2429 } | |
| 2430 if (0) fprintf(stderr, "text='%s': *out=%i\n", text, *out); | |
| 2431 | |
| 2432 return 0; | |
| 2433 } | |
| 2434 | |
| 2435 /* Reads range. | |
| 2436 * | |
| 2437 * E.g.: | |
| 2438 * text='115867-2' sets *begin=115865 *end=115866. | |
| 2439 * text='115867-1..+3' sets *begin=115866 *end=115869. | |
| 2440 * | |
| 2441 * Supported patterns for text: | |
| 2442 * <range> | |
| 2443 * <value> - returns *begin=value *end=*begin+1. | |
| 2444 * <value1>..<value2> - returns *begin=value1 *end=value2. | |
| 2445 * <value>..+<number> - returns *begin=value *end=*begin+number. | |
| 2446 * <value> | |
| 2447 * <number> | |
| 2448 * <number>+<number> | |
| 2449 * <number>-<number> | |
| 2450 * | |
| 2451 * <number>: [0-9]+ | |
| 2452 * | |
| 2453 * If not specified, *end defaults to *begin+1. | |
| 2454 * | |
| 2455 * Returns 0 on success, else -1, with *string_end pointing to first unused | |
| 2456 * character. | |
| 2457 */ | |
| 2458 static int read_number_range(const char *text, int *begin, int *end, char **string_end) | |
| 2459 { | |
| 2460 int e; | |
| 2461 e = read_number_delta(text, begin, string_end); | |
| 2462 if (e) | |
| 2463 return e; | |
| 2464 if (string_end && (*string_end)[0] == '.' && (*string_end)[1] == '.') { | |
| 2465 int relative; | |
| 2466 e = read_number((*string_end) + 2, end, &relative, string_end); | |
| 2467 if (e) | |
| 2468 return e; | |
| 2469 if (relative) | |
| 2470 *end += *begin; | |
| 2471 } else { | |
| 2472 *end = *begin + 1; | |
| 2473 } | |
| 2474 if (*end < *begin) { | |
| 2475 fprintf(stderr, "Range %i..%i has negative extent, at start of '%s'.\n", | |
| 2476 *begin, *end, text); | |
| 2477 return -1; | |
| 2478 } | |
| 2479 if (0) fprintf(stderr, "text='%s': *begin=%i *end=%i\n", text, *begin, *end); | |
| 2480 | |
| 2481 return 0; | |
| 2482 } | |
| 2483 | |
| 2484 /* Format: <range>[,<range>]+ | |
| 2485 * | |
| 2486 * For description of <range>, see read_number_range() above. | |
| 2487 * | |
| 2488 * E.g.: | |
| 2489 * MEMENTO_SQUEEZES=1234-2..+4,2345,2350..+2 | |
| 2490 */ | |
| 2491 static int Memento_add_squeezes(const char *text) | |
| 2492 { | |
| 2493 int e = 0; | |
| 2494 for(;;) { | |
| 2495 int begin; | |
| 2496 int end; | |
| 2497 char *string_end; | |
| 2498 if (!*text) | |
| 2499 break; | |
| 2500 e = read_number_range(text, &begin, &end, &string_end); | |
| 2501 if (e) | |
| 2502 break; | |
| 2503 if (*string_end && *string_end != ',') { | |
| 2504 fprintf(stderr, "Expecting comma at start of '%s'.\n", string_end); | |
| 2505 e = -1; | |
| 2506 break; | |
| 2507 } | |
| 2508 fprintf(stderr, "Adding squeeze range %i..%i.\n", | |
| 2509 begin, end); | |
| 2510 memento.squeezes_num += 1; | |
| 2511 memento.squeezes = MEMENTO_UNDERLYING_REALLOC( | |
| 2512 memento.squeezes, | |
| 2513 memento.squeezes_num * sizeof(*memento.squeezes) | |
| 2514 ); | |
| 2515 if (!memento.squeezes) { | |
| 2516 fprintf(stderr, "Failed to allocate memory for memento.squeezes_num=%i\n", | |
| 2517 memento.squeezes_num); | |
| 2518 e = -1; | |
| 2519 break; | |
| 2520 } | |
| 2521 memento.squeezes[memento.squeezes_num-1].begin = begin; | |
| 2522 memento.squeezes[memento.squeezes_num-1].end = end; | |
| 2523 | |
| 2524 if (*string_end == 0) | |
| 2525 break; | |
| 2526 text = string_end + 1; | |
| 2527 } | |
| 2528 | |
| 2529 return e; | |
| 2530 } | |
| 2531 | |
| 2532 #if defined(_WIN32) || defined(_WIN64) | |
| 2533 static int Memento_fin_win(void) | |
| 2534 { | |
| 2535 if (memento.atexitFin) | |
| 2536 Memento_fin(); | |
| 2537 return 0; | |
| 2538 } | |
| 2539 #else | |
| 2540 static void Memento_fin_unix(void) | |
| 2541 { | |
| 2542 if (memento.atexitFin) | |
| 2543 Memento_fin(); | |
| 2544 } | |
| 2545 #endif | |
| 2546 | |
| 2547 static void Memento_init(void) | |
| 2548 { | |
| 2549 char *env; | |
| 2550 memset(&memento, 0, sizeof(memento)); | |
| 2551 memento.inited = 1; | |
| 2552 memento.used.head = NULL; | |
| 2553 memento.used.tail = NULL; | |
| 2554 memento.free.head = NULL; | |
| 2555 memento.free.tail = NULL; | |
| 2556 memento.sequence = 0; | |
| 2557 memento.countdown = 1024; | |
| 2558 memento.squeezes = NULL; | |
| 2559 memento.squeezes_num = 0; | |
| 2560 memento.squeezes_pos = 0; | |
| 2561 memento.backtraceLimitFnnames = NULL; | |
| 2562 memento.backtraceLimitFnnamesNum = 0; | |
| 2563 | |
| 2564 env = getenv("MEMENTO_FAILAT"); | |
| 2565 memento.failAt = (env ? atoi(env) : 0); | |
| 2566 | |
| 2567 env = getenv("MEMENTO_BREAKAT"); | |
| 2568 memento.breakAt = (env ? atoi(env) : 0); | |
| 2569 | |
| 2570 env = getenv("MEMENTO_PARANOIA"); | |
| 2571 memento.paranoia = (env ? atoi(env) : 0); | |
| 2572 if (memento.paranoia == 0) | |
| 2573 memento.paranoia = -1024; | |
| 2574 | |
| 2575 env = getenv("MEMENTO_PARANOIDAT"); | |
| 2576 memento.paranoidAt = (env ? atoi(env) : 0); | |
| 2577 | |
| 2578 env = getenv("MEMENTO_SQUEEZEAT"); | |
| 2579 memento.squeezeAt = (env ? atoi(env) : 0); | |
| 2580 | |
| 2581 env = getenv("MEMENTO_PATTERN"); | |
| 2582 memento.pattern = (env ? atoi(env) : 0); | |
| 2583 | |
| 2584 env = getenv("MEMENTO_SHOW_DETAILED_BLOCKS"); | |
| 2585 memento.showDetailedBlocks = (env ? atoi(env) : -1); | |
| 2586 | |
| 2587 env = getenv("MEMENTO_HIDE_MULTIPLE_REALLOCS"); | |
| 2588 memento.hideMultipleReallocs = (env ? atoi(env) : 0); | |
| 2589 | |
| 2590 env = getenv("MEMENTO_HIDE_REF_CHANGE_BACKTRACES"); | |
| 2591 memento.hideRefChangeBacktraces = (env ? atoi(env) : 0); | |
| 2592 | |
| 2593 env = getenv("MEMENTO_ABORT_ON_LEAK"); | |
| 2594 memento.abortOnLeak = (env ? atoi(env) : 0); | |
| 2595 | |
| 2596 env = getenv("MEMENTO_ABORT_ON_CORRUPTION"); | |
| 2597 memento.abortOnCorruption = (env ? atoi(env) : 0); | |
| 2598 | |
| 2599 env = getenv("MEMENTO_SQUEEZES"); | |
| 2600 if (env) { | |
| 2601 int e; | |
| 2602 fprintf(stderr, "Parsing squeeze ranges in MEMENTO_SQUEEZES=%s\n", env); | |
| 2603 e = Memento_add_squeezes(env); | |
| 2604 if (e) { | |
| 2605 fprintf(stderr, "Failed to parse MEMENTO_SQUEEZES=%s\n", env); | |
| 2606 exit(1); | |
| 2607 } | |
| 2608 } | |
| 2609 | |
| 2610 env = getenv("MEMENTO_MAXMEMORY"); | |
| 2611 memento.maxMemory = (env ? atoi(env) : 0); | |
| 2612 | |
| 2613 env = getenv("MEMENTO_VERBOSE"); | |
| 2614 memento.verbose = (env ? atoi(env) : 0); | |
| 2615 | |
| 2616 env = getenv("MEMENTO_IGNORENEWDELETE"); | |
| 2617 memento.ignoreNewDelete = (env ? atoi(env) : 0); | |
| 2618 | |
| 2619 env = getenv("MEMENTO_ATEXIT_FIN"); | |
| 2620 memento.atexitFin = (env ? atoi(env) : 1); | |
| 2621 | |
| 2622 if (memento.atexitFin) { | |
| 2623 /* For Windows, we can _onexit rather than atexit. This is because | |
| 2624 * _onexit registered handlers are called when the DLL that they are | |
| 2625 * in is freed, rather than on complete closedown. This gives us a | |
| 2626 * higher chance of seeing Memento_fin called in a state when the | |
| 2627 * stack backtracing mechanism can still work. */ | |
| 2628 #if defined(_WIN32) || defined(_WIN64) | |
| 2629 _onexit(Memento_fin_win); | |
| 2630 #else | |
| 2631 atexit(Memento_fin_unix); | |
| 2632 #endif | |
| 2633 } | |
| 2634 | |
| 2635 Memento_initMutex(&memento.mutex); | |
| 2636 | |
| 2637 Memento_initStacktracer(); | |
| 2638 | |
| 2639 Memento_breakpoint(); | |
| 2640 } | |
| 2641 | |
| 2642 static void Memento_infoLocked(void *addr) | |
| 2643 { | |
| 2644 #ifdef MEMENTO_DETAILS | |
| 2645 Memento_BlkHeader *blk; | |
| 2646 | |
| 2647 blk = find_enclosing_block(&memento.used, addr, NULL); | |
| 2648 if (blk == NULL) | |
| 2649 blk = find_enclosing_block(&memento.free, addr, NULL); | |
| 2650 if (blk != NULL) | |
| 2651 showInfo(blk, NULL); | |
| 2652 #else | |
| 2653 printf("Memento not compiled with details support\n"); | |
| 2654 #endif | |
| 2655 } | |
| 2656 | |
| 2657 void Memento_info(void *addr) | |
| 2658 { | |
| 2659 MEMENTO_LOCK(); | |
| 2660 Memento_infoLocked(addr); | |
| 2661 MEMENTO_UNLOCK(); | |
| 2662 } | |
| 2663 | |
| 2664 #ifdef MEMENTO_HAS_FORK | |
| 2665 #include <unistd.h> | |
| 2666 #include <sys/wait.h> | |
| 2667 #include <time.h> | |
| 2668 #ifdef MEMENTO_STACKTRACE_METHOD | |
| 2669 #if MEMENTO_STACKTRACE_METHOD == 1 | |
| 2670 #include <signal.h> | |
| 2671 #endif | |
| 2672 #endif | |
| 2673 | |
| 2674 /* FIXME: Find some portable way of getting this */ | |
| 2675 /* MacOSX has 10240, Ubuntu seems to have 256 */ | |
| 2676 #ifndef OPEN_MAX | |
| 2677 #define OPEN_MAX 10240 | |
| 2678 #endif | |
| 2679 | |
| 2680 /* stashed_map[j] = i means that file descriptor i-1 was duplicated to j */ | |
| 2681 int stashed_map[OPEN_MAX]; | |
| 2682 | |
| 2683 static void Memento_signal(int sig) | |
| 2684 { | |
| 2685 (void)sig; | |
| 2686 fprintf(stderr, "SEGV at:\n"); | |
| 2687 memento.segv = 1; | |
| 2688 Memento_bt_internal(0); | |
| 2689 | |
| 2690 exit(1); | |
| 2691 } | |
| 2692 | |
| 2693 static int squeeze(void) | |
| 2694 { | |
| 2695 pid_t pid; | |
| 2696 int i, status; | |
| 2697 | |
| 2698 if (memento.patternBit < 0) | |
| 2699 return 1; | |
| 2700 if (memento.squeezing && memento.patternBit >= MEMENTO_MAXPATTERN) | |
| 2701 return 1; | |
| 2702 | |
| 2703 if (memento.patternBit == 0) | |
| 2704 memento.squeezeAt = memento.sequence; | |
| 2705 | |
| 2706 if (!memento.squeezing) { | |
| 2707 fprintf(stderr, "Memory squeezing @ %d\n", memento.squeezeAt); | |
| 2708 } else | |
| 2709 fprintf(stderr, "Memory squeezing @ %d (%x,%x)\n", memento.squeezeAt, memento.pattern, memento.patternBit); | |
| 2710 | |
| 2711 /* When we fork below, the child is going to snaffle all our file pointers | |
| 2712 * and potentially corrupt them. Let's make copies of all of them before | |
| 2713 * we fork, so we can restore them when we restart. */ | |
| 2714 for (i = 0; i < OPEN_MAX; i++) { | |
| 2715 if (stashed_map[i] == 0) { | |
| 2716 int j = dup(i); | |
| 2717 if (j >= 0) { | |
| 2718 stashed_map[j] = i+1; | |
| 2719 } | |
| 2720 } | |
| 2721 } | |
| 2722 | |
| 2723 fprintf(stderr, "Failing at:\n"); | |
| 2724 Memento_bt_internal(2); | |
| 2725 pid = fork(); | |
| 2726 if (pid == 0) { | |
| 2727 /* Child */ | |
| 2728 signal(SIGSEGV, Memento_signal); | |
| 2729 /* Close the dup-licated fds to avoid them getting corrupted by faulty | |
| 2730 * code. */ | |
| 2731 for (i = 0; i < OPEN_MAX; i++) { | |
| 2732 if (stashed_map[i] != 0) { | |
| 2733 /* We close duplicated fds, just in case child has some bad | |
| 2734 * code that modifies/closes random fds. */ | |
| 2735 close(i); | |
| 2736 } | |
| 2737 } | |
| 2738 /* In the child, we always fail the next allocation. */ | |
| 2739 if (memento.patternBit == 0) { | |
| 2740 memento.patternBit = 1; | |
| 2741 } else | |
| 2742 memento.patternBit <<= 1; | |
| 2743 memento.squeezing = 1; | |
| 2744 | |
| 2745 /* This is necessary to allow Memento_failThisEventLocked() near the | |
| 2746 * end to do 'return squeeze();'. */ | |
| 2747 memento.squeezes_num = 0; | |
| 2748 | |
| 2749 return 1; | |
| 2750 } | |
| 2751 | |
| 2752 /* In the parent if we hit another allocation, pass it (and record the | |
| 2753 * fact we passed it in the pattern. */ | |
| 2754 memento.pattern |= memento.patternBit; | |
| 2755 memento.patternBit <<= 1; | |
| 2756 | |
| 2757 /* Wait for pid to finish, with a timeout. */ | |
| 2758 { | |
| 2759 struct timespec tm = { 0, 10 * 1000 * 1000 }; /* 10ms = 100th sec */ | |
| 2760 int timeout = 30 * 1000 * 1000; /* time out in microseconds! */ | |
| 2761 while (waitpid(pid, &status, WNOHANG) == 0) { | |
| 2762 nanosleep(&tm, NULL); | |
| 2763 timeout -= (int)(tm.tv_nsec/1000); | |
| 2764 tm.tv_nsec *= 2; | |
| 2765 if (tm.tv_nsec > 999999999) | |
| 2766 tm.tv_nsec = 999999999; | |
| 2767 if (timeout <= 0) { | |
| 2768 char text[32]; | |
| 2769 fprintf(stderr, "Child is taking a long time to die. Killing it.\n"); | |
| 2770 sprintf(text, "kill %d", pid); | |
| 2771 system(text); | |
| 2772 break; | |
| 2773 } | |
| 2774 } | |
| 2775 } | |
| 2776 | |
| 2777 if (status != 0) { | |
| 2778 fprintf(stderr, "Child status=%d\n", status); | |
| 2779 } | |
| 2780 | |
| 2781 /* Put the files back */ | |
| 2782 for (i = 0; i < OPEN_MAX; i++) { | |
| 2783 if (stashed_map[i] != 0) { | |
| 2784 dup2(i, stashed_map[i]-1); | |
| 2785 close(i); | |
| 2786 stashed_map[i] = 0; | |
| 2787 } | |
| 2788 } | |
| 2789 | |
| 2790 return 0; | |
| 2791 } | |
| 2792 #else | |
| 2793 #include <signal.h> | |
| 2794 | |
| 2795 static void Memento_signal(int sig) | |
| 2796 { | |
| 2797 (void)sig; | |
| 2798 memento.segv = 1; | |
| 2799 /* If we just return from this function the SEGV will be unhandled, and | |
| 2800 * we'll launch into whatever JIT debugging system the OS provides. At | |
| 2801 * least fprintf(stderr, something useful first. If MEMENTO_NOJIT is set, then | |
| 2802 * just exit to avoid the JIT (and get the usual atexit handling). */ | |
| 2803 if (getenv("MEMENTO_NOJIT")) | |
| 2804 exit(1); | |
| 2805 else | |
| 2806 Memento_fin(); | |
| 2807 } | |
| 2808 | |
| 2809 static int squeeze(void) | |
| 2810 { | |
| 2811 fprintf(stderr, "Memento memory squeezing disabled as no fork!\n"); | |
| 2812 return 0; | |
| 2813 } | |
| 2814 #endif | |
| 2815 | |
| 2816 static void Memento_startFailing(void) | |
| 2817 { | |
| 2818 if (!memento.failing) { | |
| 2819 fprintf(stderr, "Starting to fail...\n"); | |
| 2820 Memento_bt(); | |
| 2821 fflush(stderr); | |
| 2822 memento.failing = 1; | |
| 2823 memento.failAt = memento.sequence; | |
| 2824 memento.nextFailAt = memento.sequence+1; | |
| 2825 memento.patternBit = 0; | |
| 2826 signal(SIGSEGV, Memento_signal); | |
| 2827 signal(SIGABRT, Memento_signal); | |
| 2828 Memento_breakpointLocked(); | |
| 2829 } | |
| 2830 } | |
| 2831 | |
| 2832 static int Memento_event(void) | |
| 2833 { | |
| 2834 int ret = 0; | |
| 2835 | |
| 2836 memento.sequence++; | |
| 2837 if ((memento.sequence >= memento.paranoidAt) && (memento.paranoidAt != 0)) { | |
| 2838 memento.paranoia = 1; | |
| 2839 memento.countdown = 1; | |
| 2840 } | |
| 2841 if (--memento.countdown == 0) { | |
| 2842 ret = Memento_checkAllMemoryLocked(); | |
| 2843 ret = (ret & 8) != 0; | |
| 2844 if (memento.paranoia > 0) | |
| 2845 memento.countdown = memento.paranoia; | |
| 2846 else | |
| 2847 { | |
| 2848 memento.countdown = -memento.paranoia; | |
| 2849 if (memento.paranoia > INT_MIN/2) | |
| 2850 memento.paranoia *= 2; | |
| 2851 } | |
| 2852 } | |
| 2853 | |
| 2854 if (memento.sequence == memento.breakAt) { | |
| 2855 fprintf(stderr, "Breaking at event %d\n", memento.breakAt); | |
| 2856 return 1; | |
| 2857 } | |
| 2858 return ret; | |
| 2859 } | |
| 2860 | |
| 2861 int Memento_sequence(void) | |
| 2862 { | |
| 2863 return memento.sequence; | |
| 2864 } | |
| 2865 | |
| 2866 int Memento_breakAt(int event) | |
| 2867 { | |
| 2868 MEMENTO_LOCK(); | |
| 2869 memento.breakAt = event; | |
| 2870 MEMENTO_UNLOCK(); | |
| 2871 return event; | |
| 2872 } | |
| 2873 | |
| 2874 static void *safe_find_block(void *ptr) | |
| 2875 { | |
| 2876 Memento_BlkHeader *block; | |
| 2877 int valid; | |
| 2878 | |
| 2879 if (ptr == NULL) | |
| 2880 return NULL; | |
| 2881 | |
| 2882 block = MEMBLK_FROMBLK(ptr); | |
| 2883 /* Sometimes wrapping allocators can mean Memento_label | |
| 2884 * is called with a value within the block, rather than | |
| 2885 * at the start of the block. If we detect this, find it | |
| 2886 * the slow way. */ | |
| 2887 VALGRIND_MAKE_MEM_DEFINED(&block->child, sizeof(block->child)); | |
| 2888 VALGRIND_MAKE_MEM_DEFINED(&block->sibling, sizeof(block->sibling)); | |
| 2889 valid = (block->child == MEMENTO_CHILD_MAGIC && | |
| 2890 block->sibling == MEMENTO_SIBLING_MAGIC); | |
| 2891 if (valid) { | |
| 2892 VALGRIND_MAKE_MEM_NOACCESS(&block->child, sizeof(block->child)); | |
| 2893 VALGRIND_MAKE_MEM_NOACCESS(&block->sibling, sizeof(block->sibling)); | |
| 2894 } | |
| 2895 if (!valid) | |
| 2896 { | |
| 2897 block = find_enclosing_block(&memento.used, ptr, NULL); | |
| 2898 } | |
| 2899 return block; | |
| 2900 } | |
| 2901 | |
| 2902 void *Memento_label(void *ptr, const char *label) | |
| 2903 { | |
| 2904 Memento_BlkHeader *block; | |
| 2905 | |
| 2906 if (ptr == NULL) | |
| 2907 return NULL; | |
| 2908 MEMENTO_LOCK(); | |
| 2909 block = safe_find_block(ptr); | |
| 2910 if (block != NULL) | |
| 2911 { | |
| 2912 VALGRIND_MAKE_MEM_DEFINED(&block->label, sizeof(block->label)); | |
| 2913 block->label = label; | |
| 2914 VALGRIND_MAKE_MEM_NOACCESS(&block->label, sizeof(block->label)); | |
| 2915 } | |
| 2916 MEMENTO_UNLOCK(); | |
| 2917 | |
| 2918 if (memento.verboseNewlineSuppressed) { | |
| 2919 if (memento.lastVerbosePtr == block) { | |
| 2920 fprintf(stderr, " (%s)", label); | |
| 2921 } | |
| 2922 } | |
| 2923 | |
| 2924 return ptr; | |
| 2925 } | |
| 2926 | |
| 2927 void Memento_tick(void) | |
| 2928 { | |
| 2929 MEMENTO_LOCK(); | |
| 2930 if (Memento_event()) Memento_breakpointLocked(); | |
| 2931 MEMENTO_UNLOCK(); | |
| 2932 } | |
| 2933 | |
| 2934 static int Memento_failThisEventLocked(void) | |
| 2935 { | |
| 2936 int failThisOne; | |
| 2937 | |
| 2938 if (Memento_event()) Memento_breakpointLocked(); | |
| 2939 | |
| 2940 if (!memento.squeezing && memento.squeezes_num) { | |
| 2941 /* Move to next relevant squeeze region if appropriate. */ | |
| 2942 for ( ; memento.squeezes_pos != memento.squeezes_num; memento.squeezes_pos++) { | |
| 2943 if (memento.sequence < memento.squeezes[memento.squeezes_pos].end) | |
| 2944 break; | |
| 2945 } | |
| 2946 | |
| 2947 /* See whether memento.sequence is within this squeeze region. */ | |
| 2948 if (memento.squeezes_pos < memento.squeezes_num) { | |
| 2949 int begin = memento.squeezes[memento.squeezes_pos].begin; | |
| 2950 int end = memento.squeezes[memento.squeezes_pos].end; | |
| 2951 if (memento.sequence >= begin && memento.sequence < end) { | |
| 2952 if (1) { | |
| 2953 fprintf(stderr, | |
| 2954 "squeezes match memento.sequence=%i: memento.squeezes_pos=%i/%i %i..%i\n", | |
| 2955 memento.sequence, | |
| 2956 memento.squeezes_pos, | |
| 2957 memento.squeezes_num, | |
| 2958 memento.squeezes[memento.squeezes_pos].begin, | |
| 2959 memento.squeezes[memento.squeezes_pos].end | |
| 2960 ); | |
| 2961 } | |
| 2962 return squeeze(); | |
| 2963 } | |
| 2964 } | |
| 2965 } | |
| 2966 | |
| 2967 if ((memento.sequence >= memento.failAt) && (memento.failAt != 0)) | |
| 2968 Memento_startFailing(); | |
| 2969 if ((memento.squeezes_num==0) && (memento.sequence >= memento.squeezeAt) && (memento.squeezeAt != 0)) | |
| 2970 return squeeze(); | |
| 2971 | |
| 2972 if (!memento.failing) | |
| 2973 return 0; | |
| 2974 failThisOne = ((memento.patternBit & memento.pattern) == 0); | |
| 2975 /* If we are failing, and we've reached the end of the pattern and we've | |
| 2976 * still got bits available in the pattern word, and we haven't already | |
| 2977 * set a nextPattern, then extend the pattern. */ | |
| 2978 if (memento.failing && | |
| 2979 ((~(memento.patternBit-1) & memento.pattern) == 0) && | |
| 2980 (memento.patternBit != 0) && | |
| 2981 memento.nextPattern == 0) | |
| 2982 { | |
| 2983 /* We'll fail this one, and set the 'next' one to pass it. */ | |
| 2984 memento.nextFailAt = memento.failAt; | |
| 2985 memento.nextPattern = memento.pattern | memento.patternBit; | |
| 2986 } | |
| 2987 memento.patternBit = (memento.patternBit ? memento.patternBit << 1 : 1); | |
| 2988 | |
| 2989 return failThisOne; | |
| 2990 } | |
| 2991 | |
| 2992 int Memento_failThisEvent(void) | |
| 2993 { | |
| 2994 int ret; | |
| 2995 | |
| 2996 if (!memento.inited) | |
| 2997 Memento_init(); | |
| 2998 | |
| 2999 MEMENTO_LOCK(); | |
| 3000 ret = Memento_failThisEventLocked(); | |
| 3001 MEMENTO_UNLOCK(); | |
| 3002 return ret; | |
| 3003 } | |
| 3004 | |
| 3005 static void *do_malloc(size_t s, int et) | |
| 3006 { | |
| 3007 Memento_BlkHeader *memblk; | |
| 3008 size_t smem = MEMBLK_SIZE(s); | |
| 3009 #ifdef MEMENTO_DETAILS | |
| 3010 Memento_hashedST *st; | |
| 3011 #endif | |
| 3012 | |
| 3013 if (Memento_failThisEventLocked()) { | |
| 3014 errno = ENOMEM; | |
| 3015 return NULL; | |
| 3016 } | |
| 3017 | |
| 3018 if (s == 0) | |
| 3019 return NULL; | |
| 3020 | |
| 3021 memento.numMallocs++; | |
| 3022 | |
| 3023 if (memento.maxMemory != 0 && memento.alloc + s > memento.maxMemory) { | |
| 3024 errno = ENOMEM; | |
| 3025 return NULL; | |
| 3026 } | |
| 3027 | |
| 3028 #ifdef MEMENTO_DETAILS | |
| 3029 st = Memento_getHashedStacktrace(); | |
| 3030 #endif | |
| 3031 | |
| 3032 memblk = MEMENTO_UNDERLYING_MALLOC(smem); | |
| 3033 if (memblk == NULL) { | |
| 3034 switch (memento.verbose) { | |
| 3035 default: | |
| 3036 if (memento.verboseNewlineSuppressed) | |
| 3037 fprintf(stderr, "\n"); | |
| 3038 fprintf(stderr, "%s failed (size="FMTZ",num=%d", | |
| 3039 eventType[et], (FMTZ_CAST)s, memento.sequence); | |
| 3040 #ifdef MEMENTO_DETAILS | |
| 3041 fprintf(stderr, ",st=%x", st->hash); | |
| 3042 #endif | |
| 3043 fprintf(stderr, ")"); | |
| 3044 memento.verboseNewlineSuppressed = 1; | |
| 3045 memento.lastVerbosePtr = memblk; | |
| 3046 break; | |
| 3047 case 2: | |
| 3048 if (memento.verboseNewlineSuppressed) | |
| 3049 fprintf(stderr, "\n"); | |
| 3050 fprintf(stderr, "%s failed (size="FMTZ"", | |
| 3051 eventType[et], (FMTZ_CAST)s); | |
| 3052 #ifdef MEMENTO_DETAILS | |
| 3053 fprintf(stderr, ",st=%x", st->hash); | |
| 3054 #endif | |
| 3055 fprintf(stderr, ")"); | |
| 3056 memento.verboseNewlineSuppressed = 1; | |
| 3057 memento.lastVerbosePtr = memblk; | |
| 3058 break; | |
| 3059 case 0: | |
| 3060 break; | |
| 3061 } | |
| 3062 return NULL; | |
| 3063 } | |
| 3064 | |
| 3065 memento.alloc += s; | |
| 3066 memento.totalAlloc += s; | |
| 3067 if (memento.peakAlloc < memento.alloc) | |
| 3068 memento.peakAlloc = memento.alloc; | |
| 3069 #ifndef MEMENTO_LEAKONLY | |
| 3070 memset(MEMBLK_TOBLK(memblk), MEMENTO_ALLOCFILL, s); | |
| 3071 #endif | |
| 3072 memblk->rawsize = s; | |
| 3073 memblk->sequence = memento.sequence; | |
| 3074 memblk->lastCheckedOK = memblk->sequence; | |
| 3075 memblk->flags = 0; | |
| 3076 memblk->label = 0; | |
| 3077 memblk->child = MEMENTO_CHILD_MAGIC; | |
| 3078 memblk->sibling = MEMENTO_SIBLING_MAGIC; | |
| 3079 #ifdef MEMENTO_DETAILS | |
| 3080 memblk->details = NULL; | |
| 3081 memblk->details_tail = &memblk->details; | |
| 3082 Memento_storeDetails(memblk, et, st); | |
| 3083 #endif /* MEMENTO_DETAILS */ | |
| 3084 Memento_addBlockHead(&memento.used, memblk, 0); | |
| 3085 | |
| 3086 if (memento.leaking > 0) | |
| 3087 memblk->flags |= Memento_Flag_KnownLeak; | |
| 3088 | |
| 3089 switch (memento.verbose) { | |
| 3090 default: | |
| 3091 if (memento.verboseNewlineSuppressed) | |
| 3092 fprintf(stderr, "\n"); | |
| 3093 fprintf(stderr, "%s "FMTP":(size="FMTZ",num=%d", | |
| 3094 eventType[et], | |
| 3095 MEMBLK_TOBLK(memblk), (FMTZ_CAST)memblk->rawsize, memblk->sequence); | |
| 3096 #ifdef MEMENTO_DETAILS | |
| 3097 fprintf(stderr, ",st=%x", st->hash); | |
| 3098 #endif | |
| 3099 if (memblk->label) | |
| 3100 fprintf(stderr, ") (%s", memblk->label); | |
| 3101 fprintf(stderr, ")"); | |
| 3102 memento.verboseNewlineSuppressed = 1; | |
| 3103 memento.lastVerbosePtr = memblk; | |
| 3104 break; | |
| 3105 case 2: | |
| 3106 if (memento.verboseNewlineSuppressed) | |
| 3107 fprintf(stderr, "\n"); | |
| 3108 fprintf(stderr, "%s (size="FMTZ"", | |
| 3109 eventType[et], | |
| 3110 (FMTZ_CAST)memblk->rawsize); | |
| 3111 #ifdef MEMENTO_DETAILS | |
| 3112 fprintf(stderr, ",st=%x", st->hash); | |
| 3113 #endif | |
| 3114 if (memblk->label) | |
| 3115 fprintf(stderr, ") (%s", memblk->label); | |
| 3116 fprintf(stderr, ")"); | |
| 3117 memento.verboseNewlineSuppressed = 1; | |
| 3118 memento.lastVerbosePtr = memblk; | |
| 3119 break; | |
| 3120 case 0: | |
| 3121 break; | |
| 3122 } | |
| 3123 | |
| 3124 return MEMBLK_TOBLK(memblk); | |
| 3125 } | |
| 3126 | |
| 3127 char *Memento_strdup(const char *text) | |
| 3128 { | |
| 3129 size_t len = strlen(text) + 1; | |
| 3130 char *ret; | |
| 3131 | |
| 3132 if (!memento.inited) | |
| 3133 Memento_init(); | |
| 3134 | |
| 3135 MEMENTO_LOCK(); | |
| 3136 ret = do_malloc(len, Memento_EventType_strdup); | |
| 3137 MEMENTO_UNLOCK(); | |
| 3138 | |
| 3139 if (ret != NULL) | |
| 3140 memcpy(ret, text, len); | |
| 3141 | |
| 3142 return ret; | |
| 3143 } | |
| 3144 | |
| 3145 #if !defined(MEMENTO_GS_HACKS) && !defined(MEMENTO_MUPDF_HACKS) | |
| 3146 int Memento_asprintf(char **ret, const char *format, ...) | |
| 3147 { | |
| 3148 va_list va; | |
| 3149 int n; | |
| 3150 int n2; | |
| 3151 | |
| 3152 if (!memento.inited) | |
| 3153 Memento_init(); | |
| 3154 | |
| 3155 va_start(va, format); | |
| 3156 n = vsnprintf(NULL, 0, format, va); | |
| 3157 va_end(va); | |
| 3158 if (n < 0) | |
| 3159 return n; | |
| 3160 | |
| 3161 MEMENTO_LOCK(); | |
| 3162 *ret = do_malloc(n+1, Memento_EventType_asprintf); | |
| 3163 MEMENTO_UNLOCK(); | |
| 3164 if (*ret == NULL) | |
| 3165 return -1; | |
| 3166 | |
| 3167 va_start(va, format); | |
| 3168 n2 = vsnprintf(*ret, n + 1, format, va); | |
| 3169 va_end(va); | |
| 3170 | |
| 3171 return n2; | |
| 3172 } | |
| 3173 | |
| 3174 int Memento_vasprintf(char **ret, const char *format, va_list ap) | |
| 3175 { | |
| 3176 int n; | |
| 3177 va_list ap2; | |
| 3178 va_copy(ap2, ap); | |
| 3179 | |
| 3180 if (!memento.inited) | |
| 3181 Memento_init(); | |
| 3182 | |
| 3183 n = vsnprintf(NULL, 0, format, ap); | |
| 3184 if (n < 0) { | |
| 3185 va_end(ap2); | |
| 3186 return n; | |
| 3187 } | |
| 3188 | |
| 3189 MEMENTO_LOCK(); | |
| 3190 *ret = do_malloc(n+1, Memento_EventType_vasprintf); | |
| 3191 MEMENTO_UNLOCK(); | |
| 3192 if (*ret == NULL) { | |
| 3193 va_end(ap2); | |
| 3194 return -1; | |
| 3195 } | |
| 3196 | |
| 3197 n = vsnprintf(*ret, n + 1, format, ap2); | |
| 3198 va_end(ap2); | |
| 3199 | |
| 3200 return n; | |
| 3201 } | |
| 3202 #endif | |
| 3203 | |
| 3204 void *Memento_malloc(size_t s) | |
| 3205 { | |
| 3206 void *ret; | |
| 3207 | |
| 3208 if (!memento.inited) | |
| 3209 Memento_init(); | |
| 3210 | |
| 3211 MEMENTO_LOCK(); | |
| 3212 ret = do_malloc(s, Memento_EventType_malloc); | |
| 3213 MEMENTO_UNLOCK(); | |
| 3214 | |
| 3215 return ret; | |
| 3216 } | |
| 3217 | |
| 3218 void *Memento_calloc(size_t n, size_t s) | |
| 3219 { | |
| 3220 void *block; | |
| 3221 | |
| 3222 if (!memento.inited) | |
| 3223 Memento_init(); | |
| 3224 | |
| 3225 MEMENTO_LOCK(); | |
| 3226 block = do_malloc(n*s, Memento_EventType_calloc); | |
| 3227 MEMENTO_UNLOCK(); | |
| 3228 if (block) | |
| 3229 memset(block, 0, n*s); | |
| 3230 | |
| 3231 return block; | |
| 3232 } | |
| 3233 | |
| 3234 #ifdef MEMENTO_TRACKREFS | |
| 3235 static void do_reference(Memento_BlkHeader *blk, int event) | |
| 3236 { | |
| 3237 #ifdef MEMENTO_DETAILS | |
| 3238 Memento_hashedST *st = Memento_getHashedStacktrace(); | |
| 3239 Memento_storeDetails(blk, event, st); | |
| 3240 #endif /* MEMENTO_DETAILS */ | |
| 3241 } | |
| 3242 #endif | |
| 3243 | |
| 3244 static int checkPointerOrNullLocked(void *blk) | |
| 3245 { | |
| 3246 if (blk == NULL) | |
| 3247 return 0; | |
| 3248 if (blk == MEMENTO_PREFILL_PTR) | |
| 3249 fprintf(stderr, "Prefill value found as pointer - buffer underrun?\n"); | |
| 3250 else if (blk == MEMENTO_POSTFILL_PTR) | |
| 3251 fprintf(stderr, "Postfill value found as pointer - buffer overrun?\n"); | |
| 3252 else if (blk == MEMENTO_ALLOCFILL_PTR) | |
| 3253 fprintf(stderr, "Allocfill value found as pointer - use of uninitialised value?\n"); | |
| 3254 else if (blk == MEMENTO_FREEFILL_PTR) | |
| 3255 fprintf(stderr, "Allocfill value found as pointer - use after free?\n"); | |
| 3256 else | |
| 3257 return 0; | |
| 3258 #ifdef MEMENTO_DETAILS | |
| 3259 fprintf(stderr, "Current backtrace:\n"); | |
| 3260 Memento_bt(); | |
| 3261 fprintf(stderr, "History:\n"); | |
| 3262 Memento_infoLocked(blk); | |
| 3263 #endif | |
| 3264 Memento_breakpointLocked(); | |
| 3265 return 1; | |
| 3266 } | |
| 3267 | |
| 3268 int Memento_checkPointerOrNull(void *blk) | |
| 3269 { | |
| 3270 int ret; | |
| 3271 MEMENTO_LOCK(); | |
| 3272 ret = checkPointerOrNullLocked(blk); | |
| 3273 MEMENTO_UNLOCK(); | |
| 3274 return ret; | |
| 3275 } | |
| 3276 | |
| 3277 static int checkBytePointerOrNullLocked(void *blk) | |
| 3278 { | |
| 3279 unsigned char i; | |
| 3280 if (blk == NULL) | |
| 3281 return 0; | |
| 3282 checkPointerOrNullLocked(blk); | |
| 3283 | |
| 3284 i = *(unsigned char *)blk; | |
| 3285 | |
| 3286 if (i == MEMENTO_PREFILL_UBYTE) | |
| 3287 fprintf(stderr, "Prefill value found - buffer underrun?\n"); | |
| 3288 else if (i == MEMENTO_POSTFILL_UBYTE) | |
| 3289 fprintf(stderr, "Postfill value found - buffer overrun?\n"); | |
| 3290 else if (i == MEMENTO_ALLOCFILL_UBYTE) | |
| 3291 fprintf(stderr, "Allocfill value found - use of uninitialised value?\n"); | |
| 3292 else if (i == MEMENTO_FREEFILL_UBYTE) | |
| 3293 fprintf(stderr, "Allocfill value found - use after free?\n"); | |
| 3294 else | |
| 3295 return 0; | |
| 3296 #ifdef MEMENTO_DETAILS | |
| 3297 fprintf(stderr, "Current backtrace:\n"); | |
| 3298 Memento_bt(); | |
| 3299 fprintf(stderr, "History:\n"); | |
| 3300 Memento_infoLocked(blk); | |
| 3301 #endif | |
| 3302 Memento_breakpointLocked(); | |
| 3303 return 1; | |
| 3304 } | |
| 3305 | |
| 3306 int Memento_checkBytePointerOrNull(void *blk) | |
| 3307 { | |
| 3308 int ret; | |
| 3309 MEMENTO_LOCK(); | |
| 3310 ret = checkBytePointerOrNullLocked(blk); | |
| 3311 MEMENTO_UNLOCK(); | |
| 3312 return ret; | |
| 3313 } | |
| 3314 | |
| 3315 static int checkShortPointerOrNullLocked(void *blk) | |
| 3316 { | |
| 3317 unsigned short i; | |
| 3318 if (blk == NULL) | |
| 3319 return 0; | |
| 3320 checkPointerOrNullLocked(blk); | |
| 3321 | |
| 3322 i = *(unsigned short *)blk; | |
| 3323 | |
| 3324 if (i == MEMENTO_PREFILL_USHORT) | |
| 3325 fprintf(stderr, "Prefill value found - buffer underrun?\n"); | |
| 3326 else if (i == MEMENTO_POSTFILL_USHORT) | |
| 3327 fprintf(stderr, "Postfill value found - buffer overrun?\n"); | |
| 3328 else if (i == MEMENTO_ALLOCFILL_USHORT) | |
| 3329 fprintf(stderr, "Allocfill value found - use of uninitialised value?\n"); | |
| 3330 else if (i == MEMENTO_FREEFILL_USHORT) | |
| 3331 fprintf(stderr, "Allocfill value found - use after free?\n"); | |
| 3332 else | |
| 3333 return 0; | |
| 3334 #ifdef MEMENTO_DETAILS | |
| 3335 fprintf(stderr, "Current backtrace:\n"); | |
| 3336 Memento_bt(); | |
| 3337 fprintf(stderr, "History:\n"); | |
| 3338 Memento_infoLocked(blk); | |
| 3339 #endif | |
| 3340 Memento_breakpointLocked(); | |
| 3341 return 1; | |
| 3342 } | |
| 3343 | |
| 3344 int Memento_checkShortPointerOrNull(void *blk) | |
| 3345 { | |
| 3346 int ret; | |
| 3347 MEMENTO_LOCK(); | |
| 3348 ret = checkShortPointerOrNullLocked(blk); | |
| 3349 MEMENTO_UNLOCK(); | |
| 3350 return ret; | |
| 3351 } | |
| 3352 | |
| 3353 static int checkIntPointerOrNullLocked(void *blk) | |
| 3354 { | |
| 3355 unsigned int i; | |
| 3356 if (blk == NULL) | |
| 3357 return 0; | |
| 3358 checkPointerOrNullLocked(blk); | |
| 3359 | |
| 3360 i = *(unsigned int *)blk; | |
| 3361 | |
| 3362 if (i == MEMENTO_PREFILL_UINT) | |
| 3363 fprintf(stderr, "Prefill value found - buffer underrun?\n"); | |
| 3364 else if (i == MEMENTO_POSTFILL_UINT) | |
| 3365 fprintf(stderr, "Postfill value found - buffer overrun?\n"); | |
| 3366 else if (i == MEMENTO_ALLOCFILL_UINT) | |
| 3367 fprintf(stderr, "Allocfill value found - use of uninitialised value?\n"); | |
| 3368 else if (i == MEMENTO_FREEFILL_UINT) | |
| 3369 fprintf(stderr, "Allocfill value found - use after free?\n"); | |
| 3370 else | |
| 3371 return 0; | |
| 3372 #ifdef MEMENTO_DETAILS | |
| 3373 fprintf(stderr, "Current backtrace:\n"); | |
| 3374 Memento_bt(); | |
| 3375 fprintf(stderr, "History:\n"); | |
| 3376 Memento_infoLocked(blk); | |
| 3377 #endif | |
| 3378 Memento_breakpointLocked(); | |
| 3379 return 1; | |
| 3380 } | |
| 3381 | |
| 3382 int Memento_checkIntPointerOrNull(void *blk) | |
| 3383 { | |
| 3384 int ret; | |
| 3385 MEMENTO_LOCK(); | |
| 3386 ret = checkIntPointerOrNullLocked(blk); | |
| 3387 MEMENTO_UNLOCK(); | |
| 3388 return ret; | |
| 3389 } | |
| 3390 | |
| 3391 #ifdef MEMENTO_TRACKREFS | |
| 3392 static void *do_takeRef(void *blk) | |
| 3393 { | |
| 3394 do_reference(safe_find_block(blk), Memento_EventType_takeRef); | |
| 3395 return blk; | |
| 3396 } | |
| 3397 | |
| 3398 static void *do_takeRefAndUnlock(void *blk) | |
| 3399 { | |
| 3400 do_reference(safe_find_block(blk), Memento_EventType_takeRef); | |
| 3401 MEMENTO_UNLOCK(); | |
| 3402 return blk; | |
| 3403 } | |
| 3404 | |
| 3405 static void *do_dropRef(void *blk) | |
| 3406 { | |
| 3407 do_reference(safe_find_block(blk), Memento_EventType_dropRef); | |
| 3408 return blk; | |
| 3409 } | |
| 3410 | |
| 3411 static void *do_dropRefAndUnlock(void *blk) | |
| 3412 { | |
| 3413 do_reference(safe_find_block(blk), Memento_EventType_dropRef); | |
| 3414 MEMENTO_UNLOCK(); | |
| 3415 return blk; | |
| 3416 } | |
| 3417 #endif | |
| 3418 | |
| 3419 void *Memento_takeByteRef(void *blk) | |
| 3420 { | |
| 3421 #ifdef MEMENTO_TRACKREFS | |
| 3422 if (!memento.inited) | |
| 3423 Memento_init(); | |
| 3424 | |
| 3425 MEMENTO_LOCK(); | |
| 3426 if (Memento_event()) Memento_breakpointLocked(); | |
| 3427 | |
| 3428 if (!blk) { | |
| 3429 MEMENTO_UNLOCK(); | |
| 3430 return NULL; | |
| 3431 } | |
| 3432 | |
| 3433 (void)checkBytePointerOrNullLocked(blk); | |
| 3434 | |
| 3435 return do_takeRefAndUnlock(blk); | |
| 3436 #else | |
| 3437 return blk; | |
| 3438 #endif | |
| 3439 } | |
| 3440 | |
| 3441 void *Memento_takeShortRef(void *blk) | |
| 3442 { | |
| 3443 #ifdef MEMENTO_TRACKREFS | |
| 3444 if (!memento.inited) | |
| 3445 Memento_init(); | |
| 3446 | |
| 3447 MEMENTO_LOCK(); | |
| 3448 if (Memento_event()) Memento_breakpointLocked(); | |
| 3449 | |
| 3450 if (!blk) { | |
| 3451 MEMENTO_UNLOCK(); | |
| 3452 return NULL; | |
| 3453 } | |
| 3454 | |
| 3455 (void)checkShortPointerOrNullLocked(blk); | |
| 3456 | |
| 3457 return do_takeRefAndUnlock(blk); | |
| 3458 #else | |
| 3459 return blk; | |
| 3460 #endif | |
| 3461 } | |
| 3462 | |
| 3463 void *Memento_takeIntRef(void *blk) | |
| 3464 { | |
| 3465 #ifdef MEMENTO_TRACKREFS | |
| 3466 if (!memento.inited) | |
| 3467 Memento_init(); | |
| 3468 | |
| 3469 MEMENTO_LOCK(); | |
| 3470 if (Memento_event()) Memento_breakpointLocked(); | |
| 3471 | |
| 3472 if (!blk) { | |
| 3473 MEMENTO_UNLOCK(); | |
| 3474 return NULL; | |
| 3475 } | |
| 3476 | |
| 3477 (void)checkIntPointerOrNullLocked(blk); | |
| 3478 | |
| 3479 return do_takeRefAndUnlock(blk); | |
| 3480 #else | |
| 3481 return blk; | |
| 3482 #endif | |
| 3483 } | |
| 3484 | |
| 3485 void *Memento_takeRef(void *blk) | |
| 3486 { | |
| 3487 #ifdef MEMENTO_TRACKREFS | |
| 3488 if (!memento.inited) | |
| 3489 Memento_init(); | |
| 3490 | |
| 3491 MEMENTO_LOCK(); | |
| 3492 if (Memento_event()) Memento_breakpointLocked(); | |
| 3493 | |
| 3494 if (!blk) { | |
| 3495 MEMENTO_UNLOCK(); | |
| 3496 return NULL; | |
| 3497 } | |
| 3498 | |
| 3499 return do_takeRefAndUnlock(blk); | |
| 3500 #else | |
| 3501 return blk; | |
| 3502 #endif | |
| 3503 } | |
| 3504 | |
| 3505 void *Memento_dropByteRef(void *blk) | |
| 3506 { | |
| 3507 #ifdef MEMENTO_TRACKREFS | |
| 3508 if (!memento.inited) | |
| 3509 Memento_init(); | |
| 3510 | |
| 3511 MEMENTO_LOCK(); | |
| 3512 if (Memento_event()) Memento_breakpointLocked(); | |
| 3513 | |
| 3514 if (!blk) { | |
| 3515 MEMENTO_UNLOCK(); | |
| 3516 return NULL; | |
| 3517 } | |
| 3518 | |
| 3519 checkBytePointerOrNullLocked(blk); | |
| 3520 | |
| 3521 return do_dropRefAndUnlock(blk); | |
| 3522 #else | |
| 3523 return blk; | |
| 3524 #endif | |
| 3525 } | |
| 3526 | |
| 3527 void *Memento_dropShortRef(void *blk) | |
| 3528 { | |
| 3529 #ifdef MEMENTO_TRACKREFS | |
| 3530 if (!memento.inited) | |
| 3531 Memento_init(); | |
| 3532 | |
| 3533 MEMENTO_LOCK(); | |
| 3534 if (Memento_event()) Memento_breakpointLocked(); | |
| 3535 | |
| 3536 if (!blk) { | |
| 3537 MEMENTO_UNLOCK(); | |
| 3538 return NULL; | |
| 3539 } | |
| 3540 | |
| 3541 checkShortPointerOrNullLocked(blk); | |
| 3542 | |
| 3543 return do_dropRefAndUnlock(blk); | |
| 3544 #else | |
| 3545 return blk; | |
| 3546 #endif | |
| 3547 } | |
| 3548 | |
| 3549 void *Memento_dropIntRef(void *blk) | |
| 3550 { | |
| 3551 #ifdef MEMENTO_TRACKREFS | |
| 3552 if (!memento.inited) | |
| 3553 Memento_init(); | |
| 3554 | |
| 3555 MEMENTO_LOCK(); | |
| 3556 if (Memento_event()) Memento_breakpointLocked(); | |
| 3557 | |
| 3558 if (!blk) { | |
| 3559 MEMENTO_UNLOCK(); | |
| 3560 return NULL; | |
| 3561 } | |
| 3562 | |
| 3563 checkIntPointerOrNullLocked(blk); | |
| 3564 | |
| 3565 return do_dropRefAndUnlock(blk); | |
| 3566 #else | |
| 3567 return blk; | |
| 3568 #endif | |
| 3569 } | |
| 3570 | |
| 3571 void *Memento_dropRef(void *blk) | |
| 3572 { | |
| 3573 #ifdef MEMENTO_TRACKREFS | |
| 3574 if (!memento.inited) | |
| 3575 Memento_init(); | |
| 3576 | |
| 3577 MEMENTO_LOCK(); | |
| 3578 if (Memento_event()) Memento_breakpointLocked(); | |
| 3579 | |
| 3580 if (!blk) { | |
| 3581 MEMENTO_UNLOCK(); | |
| 3582 return NULL; | |
| 3583 } | |
| 3584 | |
| 3585 return do_dropRefAndUnlock(blk); | |
| 3586 #else | |
| 3587 return blk; | |
| 3588 #endif | |
| 3589 } | |
| 3590 | |
| 3591 void *Memento_adjustRef(void *blk, int adjust) | |
| 3592 { | |
| 3593 #ifdef MEMENTO_TRACKREFS | |
| 3594 if (!memento.inited) | |
| 3595 Memento_init(); | |
| 3596 | |
| 3597 MEMENTO_LOCK(); | |
| 3598 if (Memento_event()) Memento_breakpointLocked(); | |
| 3599 | |
| 3600 if (blk == NULL) { | |
| 3601 MEMENTO_UNLOCK(); | |
| 3602 return NULL; | |
| 3603 } | |
| 3604 | |
| 3605 while (adjust > 0) | |
| 3606 { | |
| 3607 do_takeRef(blk); | |
| 3608 adjust--; | |
| 3609 } | |
| 3610 while (adjust < 0) | |
| 3611 { | |
| 3612 do_dropRef(blk); | |
| 3613 adjust++; | |
| 3614 } | |
| 3615 | |
| 3616 MEMENTO_UNLOCK(); | |
| 3617 #endif | |
| 3618 return blk; | |
| 3619 } | |
| 3620 | |
| 3621 void *Memento_reference(void *blk) | |
| 3622 { | |
| 3623 #ifdef MEMENTO_TRACKREFS | |
| 3624 if (!blk) | |
| 3625 return NULL; | |
| 3626 | |
| 3627 if (!memento.inited) | |
| 3628 Memento_init(); | |
| 3629 | |
| 3630 MEMENTO_LOCK(); | |
| 3631 do_reference(safe_find_block(blk), Memento_EventType_reference); | |
| 3632 MEMENTO_UNLOCK(); | |
| 3633 #endif | |
| 3634 return blk; | |
| 3635 } | |
| 3636 | |
| 3637 /* Treat blocks from the user with suspicion, and check them the slow | |
| 3638 * but safe way. */ | |
| 3639 static int checkBlockUser(Memento_BlkHeader *memblk, const char *action) | |
| 3640 { | |
| 3641 #ifndef MEMENTO_LEAKONLY | |
| 3642 BlkCheckData data; | |
| 3643 | |
| 3644 memset(&data, 0, sizeof(data)); | |
| 3645 Memento_appBlockUser(&memento.used, Memento_Internal_checkAllocedBlock, | |
| 3646 &data, memblk); | |
| 3647 if (!data.found) { | |
| 3648 /* Failure! */ | |
| 3649 fprintf(stderr, "Attempt to %s block ", action); | |
| 3650 showBlock(memblk, 32); | |
| 3651 fprintf(stderr, "\n"); | |
| 3652 Memento_breakpointLocked(); | |
| 3653 return 1; | |
| 3654 } else if (data.preCorrupt || data.postCorrupt) { | |
| 3655 fprintf(stderr, "Block "); | |
| 3656 showBlock(memblk, ' '); | |
| 3657 fprintf(stderr, " found to be corrupted on %s!\n", action); | |
| 3658 if (data.preCorrupt) { | |
| 3659 fprintf(stderr, "Preguard corrupted\n"); | |
| 3660 } | |
| 3661 if (data.postCorrupt) { | |
| 3662 fprintf(stderr, "Postguard corrupted\n"); | |
| 3663 } | |
| 3664 fprintf(stderr, "Block last checked OK at allocation %d. Now %d.\n", | |
| 3665 memblk->lastCheckedOK, memento.sequence); | |
| 3666 if ((memblk->flags & Memento_Flag_Reported) == 0) | |
| 3667 { | |
| 3668 memblk->flags |= Memento_Flag_Reported; | |
| 3669 Memento_breakpointLocked(); | |
| 3670 } | |
| 3671 return 1; | |
| 3672 } | |
| 3673 #endif | |
| 3674 return 0; | |
| 3675 } | |
| 3676 | |
| 3677 static int checkBlock(Memento_BlkHeader *memblk, const char *action) | |
| 3678 { | |
| 3679 #ifndef MEMENTO_LEAKONLY | |
| 3680 BlkCheckData data; | |
| 3681 #endif | |
| 3682 | |
| 3683 if (memblk->child != MEMENTO_CHILD_MAGIC || | |
| 3684 memblk->sibling != MEMENTO_SIBLING_MAGIC) | |
| 3685 { | |
| 3686 /* Failure! */ | |
| 3687 fprintf(stderr, "Attempt to %s invalid block ", action); | |
| 3688 showBlock(memblk, 32); | |
| 3689 fprintf(stderr, "\n"); | |
| 3690 return 2; | |
| 3691 } | |
| 3692 | |
| 3693 #ifndef MEMENTO_LEAKONLY | |
| 3694 memset(&data, 0, sizeof(data)); | |
| 3695 Memento_appBlock(&memento.used, Memento_Internal_checkAllocedBlock, | |
| 3696 &data, memblk); | |
| 3697 if (!data.found) { | |
| 3698 /* Failure! */ | |
| 3699 fprintf(stderr, "Attempt to %s block ", action); | |
| 3700 showBlock(memblk, 32); | |
| 3701 fprintf(stderr, "\n"); | |
| 3702 return 2; | |
| 3703 } else if (data.preCorrupt || data.postCorrupt) { | |
| 3704 fprintf(stderr, "Block "); | |
| 3705 showBlock(memblk, ' '); | |
| 3706 fprintf(stderr, " found to be corrupted on %s!\n", action); | |
| 3707 if (data.preCorrupt) { | |
| 3708 fprintf(stderr, "Preguard corrupted\n"); | |
| 3709 } | |
| 3710 if (data.postCorrupt) { | |
| 3711 fprintf(stderr, "Postguard corrupted\n"); | |
| 3712 } | |
| 3713 fprintf(stderr, "Block last checked OK at allocation %d. Now %d.\n", | |
| 3714 memblk->lastCheckedOK, memento.sequence); | |
| 3715 if ((memblk->flags & Memento_Flag_Reported) == 0) | |
| 3716 { | |
| 3717 memblk->flags |= Memento_Flag_Reported; | |
| 3718 return 2; | |
| 3719 } | |
| 3720 return 1; | |
| 3721 } | |
| 3722 #endif | |
| 3723 return 0; | |
| 3724 } | |
| 3725 | |
| 3726 static void do_free(void *blk, int et) | |
| 3727 { | |
| 3728 Memento_BlkHeader *memblk; | |
| 3729 int ret; | |
| 3730 #ifdef MEMENTO_DETAILS | |
| 3731 Memento_hashedST *st; | |
| 3732 #endif | |
| 3733 | |
| 3734 if (Memento_event()) Memento_breakpointLocked(); | |
| 3735 | |
| 3736 if (blk == NULL) | |
| 3737 return; | |
| 3738 | |
| 3739 memblk = MEMBLK_FROMBLK(blk); | |
| 3740 VALGRIND_MAKE_MEM_DEFINED(memblk, sizeof(*memblk)); | |
| 3741 ret = checkBlock(memblk, "free"); | |
| 3742 if (ret) | |
| 3743 { | |
| 3744 if (ret & 2) | |
| 3745 Memento_breakpoint(); | |
| 3746 if (memento.abortOnCorruption) { | |
| 3747 fprintf(stderr, "*** memblk corrupted, calling abort()\n"); | |
| 3748 abort(); | |
| 3749 } | |
| 3750 return; | |
| 3751 } | |
| 3752 | |
| 3753 #ifdef MEMENTO_DETAILS | |
| 3754 st = Memento_getHashedStacktrace(); | |
| 3755 #endif | |
| 3756 | |
| 3757 switch (memento.verbose) { | |
| 3758 default: | |
| 3759 if (memento.verboseNewlineSuppressed) { | |
| 3760 fprintf(stderr, "\n"); | |
| 3761 memento.verboseNewlineSuppressed = 0; | |
| 3762 } | |
| 3763 fprintf(stderr, "%s "FMTP":(size="FMTZ",num=%d", | |
| 3764 eventType[et], | |
| 3765 MEMBLK_TOBLK(memblk), (FMTZ_CAST)memblk->rawsize, memblk->sequence); | |
| 3766 #ifdef MEMENTO_DETAILS | |
| 3767 fprintf(stderr, ",hash=%x", st->hash); | |
| 3768 #endif | |
| 3769 if (memblk->label) | |
| 3770 fprintf(stderr, ") (%s", memblk->label); | |
| 3771 fprintf(stderr, ")\n"); | |
| 3772 break; | |
| 3773 case 2: | |
| 3774 if (memento.verboseNewlineSuppressed) { | |
| 3775 fprintf(stderr, "\n"); | |
| 3776 memento.verboseNewlineSuppressed = 0; | |
| 3777 } | |
| 3778 fprintf(stderr, "%s (size="FMTZ, | |
| 3779 eventType[et], | |
| 3780 (FMTZ_CAST)memblk->rawsize); | |
| 3781 #ifdef MEMENTO_DETAILS | |
| 3782 fprintf(stderr, ",hash=%x", st->hash); | |
| 3783 #endif | |
| 3784 if (memblk->label) | |
| 3785 fprintf(stderr, ") (%s", memblk->label); | |
| 3786 fprintf(stderr, ")\n"); | |
| 3787 break; | |
| 3788 case 0: | |
| 3789 break; | |
| 3790 } | |
| 3791 | |
| 3792 #ifdef MEMENTO_DETAILS | |
| 3793 Memento_storeDetails(memblk, et, st); | |
| 3794 #endif | |
| 3795 | |
| 3796 VALGRIND_MAKE_MEM_DEFINED(memblk, sizeof(*memblk)); | |
| 3797 if (memblk->flags & Memento_Flag_BreakOnFree) | |
| 3798 Memento_breakpointLocked(); | |
| 3799 | |
| 3800 memento.alloc -= memblk->rawsize; | |
| 3801 memento.numFrees++; | |
| 3802 | |
| 3803 Memento_removeBlock(&memento.used, memblk); | |
| 3804 | |
| 3805 VALGRIND_MAKE_MEM_DEFINED(memblk, sizeof(*memblk)); | |
| 3806 if (Memento_Internal_makeSpace(MEMBLK_SIZE(memblk->rawsize))) { | |
| 3807 VALGRIND_MAKE_MEM_DEFINED(memblk, sizeof(*memblk)); | |
| 3808 VALGRIND_MAKE_MEM_DEFINED(MEMBLK_TOBLK(memblk), | |
| 3809 memblk->rawsize + Memento_PostSize); | |
| 3810 #ifndef MEMENTO_LEAKONLY | |
| 3811 memset(MEMBLK_TOBLK(memblk), MEMENTO_FREEFILL, memblk->rawsize); | |
| 3812 #endif | |
| 3813 memblk->flags |= Memento_Flag_Freed; | |
| 3814 Memento_addBlockTail(&memento.free, memblk, 1); | |
| 3815 } else { | |
| 3816 free_block(memblk); | |
| 3817 } | |
| 3818 } | |
| 3819 | |
| 3820 void Memento_free(void *blk) | |
| 3821 { | |
| 3822 if (!memento.inited) | |
| 3823 Memento_init(); | |
| 3824 | |
| 3825 MEMENTO_LOCK(); | |
| 3826 do_free(blk, Memento_EventType_free); | |
| 3827 MEMENTO_UNLOCK(); | |
| 3828 } | |
| 3829 | |
| 3830 static void *do_realloc(void *blk, size_t newsize, int type) | |
| 3831 { | |
| 3832 Memento_BlkHeader *memblk, *newmemblk; | |
| 3833 size_t newsizemem; | |
| 3834 int flags, ret; | |
| 3835 size_t oldsize; | |
| 3836 #ifdef MEMENTO_DETAILS | |
| 3837 Memento_hashedST *st; | |
| 3838 #endif | |
| 3839 char oldptrstr[100]; | |
| 3840 | |
| 3841 | |
| 3842 if (Memento_failThisEventLocked()) { | |
| 3843 errno = ENOMEM; | |
| 3844 return NULL; | |
| 3845 } | |
| 3846 | |
| 3847 #ifdef MEMENTO_DETAILS | |
| 3848 st = Memento_getHashedStacktrace(); | |
| 3849 #endif | |
| 3850 | |
| 3851 memblk = MEMBLK_FROMBLK(blk); | |
| 3852 VALGRIND_MAKE_MEM_DEFINED(memblk, sizeof(*memblk)); | |
| 3853 ret = checkBlock(memblk, "realloc"); | |
| 3854 if (ret) { | |
| 3855 switch (memento.verbose) { | |
| 3856 default: | |
| 3857 if (memento.verboseNewlineSuppressed) { | |
| 3858 fprintf(stderr, "\n"); | |
| 3859 memento.verboseNewlineSuppressed = 0; | |
| 3860 } | |
| 3861 fprintf(stderr, "%s bad block "FMTP":(size=?=>"FMTZ", num=?, now=%d", | |
| 3862 eventType[type], | |
| 3863 MEMBLK_TOBLK(memblk), | |
| 3864 (FMTZ_CAST)newsize, memento.sequence); | |
| 3865 #ifdef MEMENTO_DETAILS | |
| 3866 fprintf(stderr, ",hash=%x", st->hash); | |
| 3867 #endif | |
| 3868 fprintf(stderr, ")\n"); | |
| 3869 break; | |
| 3870 case 2: | |
| 3871 if (memento.verboseNewlineSuppressed) { | |
| 3872 fprintf(stderr, "\n"); | |
| 3873 memento.verboseNewlineSuppressed = 0; | |
| 3874 } | |
| 3875 fprintf(stderr, "%s bad block (size=?=>"FMTZ, | |
| 3876 eventType[type], | |
| 3877 (FMTZ_CAST)newsize); | |
| 3878 #ifdef MEMENTO_DETAILS | |
| 3879 fprintf(stderr, ",hash=%x", st->hash); | |
| 3880 #endif | |
| 3881 fprintf(stderr, ")\n"); | |
| 3882 break; | |
| 3883 case 0: | |
| 3884 break; | |
| 3885 } | |
| 3886 if (ret == 2) | |
| 3887 Memento_breakpoint(); | |
| 3888 errno = ENOMEM; | |
| 3889 return NULL; | |
| 3890 } | |
| 3891 | |
| 3892 #ifdef MEMENTO_DETAILS | |
| 3893 Memento_storeDetails(memblk, type, st); | |
| 3894 #endif | |
| 3895 | |
| 3896 VALGRIND_MAKE_MEM_DEFINED(memblk, sizeof(*memblk)); | |
| 3897 if (memblk->flags & Memento_Flag_BreakOnRealloc) | |
| 3898 Memento_breakpointLocked(); | |
| 3899 | |
| 3900 VALGRIND_MAKE_MEM_DEFINED(memblk, sizeof(*memblk)); | |
| 3901 oldsize = memblk->rawsize; | |
| 3902 if (memento.maxMemory != 0 && memento.alloc - oldsize + newsize > memento.maxMemory) { | |
| 3903 switch (memento.verbose) { | |
| 3904 default: | |
| 3905 if (memento.verboseNewlineSuppressed) { | |
| 3906 fprintf(stderr, "\n"); | |
| 3907 memento.verboseNewlineSuppressed = 0; | |
| 3908 } | |
| 3909 fprintf(stderr, "%s failing (memory limit exceeded) "FMTP":(size="FMTZ"=>"FMTZ", num=%d, now=%d", | |
| 3910 eventType[type], MEMBLK_TOBLK(memblk), | |
| 3911 (FMTZ_CAST)oldsize, (FMTZ_CAST)newsize, | |
| 3912 memblk->sequence, memento.sequence); | |
| 3913 #ifdef MEMENTO_DETAILS | |
| 3914 fprintf(stderr, ",hash=%x", st->hash); | |
| 3915 #endif | |
| 3916 if (memblk->label) | |
| 3917 fprintf(stderr, ") (%s", memblk->label); | |
| 3918 fprintf(stderr, ")\n"); | |
| 3919 break; | |
| 3920 case 2: | |
| 3921 if (memento.verboseNewlineSuppressed) { | |
| 3922 fprintf(stderr, "\n"); | |
| 3923 memento.verboseNewlineSuppressed = 0; | |
| 3924 } | |
| 3925 fprintf(stderr, "%s failing (memory limit exceeded) (size="FMTZ"=>"FMTZ, | |
| 3926 eventType[type], (FMTZ_CAST)oldsize, (FMTZ_CAST)newsize); | |
| 3927 #ifdef MEMENTO_DETAILS | |
| 3928 fprintf(stderr, ",hash=%x", st->hash); | |
| 3929 #endif | |
| 3930 if (memblk->label) | |
| 3931 fprintf(stderr, ") (%s", memblk->label); | |
| 3932 fprintf(stderr, ")\n"); | |
| 3933 break; | |
| 3934 case 0: | |
| 3935 break; | |
| 3936 } | |
| 3937 errno = ENOMEM; | |
| 3938 return NULL; | |
| 3939 } | |
| 3940 | |
| 3941 newsizemem = MEMBLK_SIZE(newsize); | |
| 3942 Memento_removeBlock(&memento.used, memblk); | |
| 3943 VALGRIND_MAKE_MEM_DEFINED(memblk, sizeof(*memblk)); | |
| 3944 flags = memblk->flags; | |
| 3945 snprintf(oldptrstr, sizeof(oldptrstr), FMTP, MEMBLK_TOBLK(memblk)); | |
| 3946 newmemblk = MEMENTO_UNDERLYING_REALLOC(memblk, newsizemem); | |
| 3947 if (newmemblk == NULL) | |
| 3948 { | |
| 3949 switch (memento.verbose) { | |
| 3950 default: | |
| 3951 if (memento.verboseNewlineSuppressed) { | |
| 3952 fprintf(stderr, "\n"); | |
| 3953 memento.verboseNewlineSuppressed = 0; | |
| 3954 } | |
| 3955 fprintf(stderr, "%s failed "FMTP":(size="FMTZ"=>"FMTZ", num=%d, now=%d", | |
| 3956 eventType[type], MEMBLK_TOBLK(memblk), | |
| 3957 (FMTZ_CAST)oldsize, (FMTZ_CAST)newsize, | |
| 3958 memblk->sequence, memento.sequence); | |
| 3959 #ifdef MEMENTO_DETAILS | |
| 3960 fprintf(stderr, ",hash=%x", st->hash); | |
| 3961 #endif | |
| 3962 if (memblk->label) | |
| 3963 fprintf(stderr, ") (%s", newmemblk->label); | |
| 3964 fprintf(stderr, ")\n"); | |
| 3965 break; | |
| 3966 case 2: | |
| 3967 if (memento.verboseNewlineSuppressed) { | |
| 3968 fprintf(stderr, "\n"); | |
| 3969 memento.verboseNewlineSuppressed = 0; | |
| 3970 } | |
| 3971 fprintf(stderr, "%s failed (size="FMTZ"=>"FMTZ, | |
| 3972 eventType[type], | |
| 3973 (FMTZ_CAST)oldsize, (FMTZ_CAST)newsize); | |
| 3974 #ifdef MEMENTO_DETAILS | |
| 3975 fprintf(stderr, ",hash=%x", st->hash); | |
| 3976 #endif | |
| 3977 if (memblk->label) | |
| 3978 fprintf(stderr, ") (%s", newmemblk->label); | |
| 3979 fprintf(stderr, ")\n"); | |
| 3980 break; | |
| 3981 case 0: | |
| 3982 break; | |
| 3983 } | |
| 3984 Memento_addBlockHead(&memento.used, memblk, 2); | |
| 3985 return NULL; | |
| 3986 } | |
| 3987 memento.numReallocs++; | |
| 3988 memento.totalAlloc += newsize; | |
| 3989 memento.alloc -= newmemblk->rawsize; | |
| 3990 memento.alloc += newsize; | |
| 3991 if (memento.peakAlloc < memento.alloc) | |
| 3992 memento.peakAlloc = memento.alloc; | |
| 3993 newmemblk->flags = flags; | |
| 3994 #ifndef MEMENTO_LEAKONLY | |
| 3995 if (newmemblk->rawsize < newsize) { | |
| 3996 char *newbytes = ((char *)MEMBLK_TOBLK(newmemblk))+newmemblk->rawsize; | |
| 3997 VALGRIND_MAKE_MEM_DEFINED(newbytes, newsize - newmemblk->rawsize); | |
| 3998 memset(newbytes, MEMENTO_ALLOCFILL, newsize - newmemblk->rawsize); | |
| 3999 VALGRIND_MAKE_MEM_UNDEFINED(newbytes, newsize - newmemblk->rawsize); | |
| 4000 } | |
| 4001 #endif | |
| 4002 newmemblk->rawsize = newsize; | |
| 4003 #ifndef MEMENTO_LEAKONLY | |
| 4004 VALGRIND_MAKE_MEM_DEFINED(newmemblk->preblk, Memento_PreSize); | |
| 4005 memset(newmemblk->preblk, MEMENTO_PREFILL, Memento_PreSize); | |
| 4006 VALGRIND_MAKE_MEM_UNDEFINED(newmemblk->preblk, Memento_PreSize); | |
| 4007 VALGRIND_MAKE_MEM_DEFINED(MEMBLK_POSTPTR(newmemblk), Memento_PostSize); | |
| 4008 memset(MEMBLK_POSTPTR(newmemblk), MEMENTO_POSTFILL, Memento_PostSize); | |
| 4009 VALGRIND_MAKE_MEM_UNDEFINED(MEMBLK_POSTPTR(newmemblk), Memento_PostSize); | |
| 4010 #endif | |
| 4011 | |
| 4012 switch (memento.verbose) { | |
| 4013 default: | |
| 4014 if (memento.verboseNewlineSuppressed) { | |
| 4015 fprintf(stderr, "\n"); | |
| 4016 memento.verboseNewlineSuppressed = 0; | |
| 4017 } | |
| 4018 fprintf(stderr, "%s %s=>"FMTP":(size="FMTZ"=>"FMTZ", num=%d, now=%d", | |
| 4019 eventType[type], | |
| 4020 oldptrstr, MEMBLK_TOBLK(newmemblk), | |
| 4021 (FMTZ_CAST)oldsize, (FMTZ_CAST)newsize, | |
| 4022 newmemblk->sequence, memento.sequence); | |
| 4023 #ifdef MEMENTO_DETAILS | |
| 4024 fprintf(stderr, ",hash=%x", st->hash); | |
| 4025 #endif | |
| 4026 if (newmemblk->label) | |
| 4027 fprintf(stderr, ") (%s", newmemblk->label); | |
| 4028 fprintf(stderr, ")\n"); | |
| 4029 break; | |
| 4030 case 2: | |
| 4031 if (memento.verboseNewlineSuppressed) { | |
| 4032 fprintf(stderr, "\n"); | |
| 4033 memento.verboseNewlineSuppressed = 0; | |
| 4034 } | |
| 4035 fprintf(stderr, "%s (size="FMTZ"=>"FMTZ, | |
| 4036 eventType[type], | |
| 4037 (FMTZ_CAST)oldsize, (FMTZ_CAST)newsize); | |
| 4038 #ifdef MEMENTO_DETAILS | |
| 4039 fprintf(stderr, ",hash=%x", st->hash); | |
| 4040 #endif | |
| 4041 if (newmemblk->label) | |
| 4042 fprintf(stderr, ") (%s", newmemblk->label); | |
| 4043 fprintf(stderr, ")\n"); | |
| 4044 break; | |
| 4045 case 0: | |
| 4046 break; | |
| 4047 } | |
| 4048 | |
| 4049 Memento_addBlockHead(&memento.used, newmemblk, 2); | |
| 4050 return MEMBLK_TOBLK(newmemblk); | |
| 4051 } | |
| 4052 | |
| 4053 void *Memento_realloc(void *blk, size_t newsize) | |
| 4054 { | |
| 4055 void *ret; | |
| 4056 | |
| 4057 if (!memento.inited) | |
| 4058 Memento_init(); | |
| 4059 | |
| 4060 if (blk == NULL) | |
| 4061 { | |
| 4062 MEMENTO_LOCK(); | |
| 4063 ret = do_malloc(newsize, Memento_EventType_realloc); | |
| 4064 MEMENTO_UNLOCK(); | |
| 4065 if (!ret) errno = ENOMEM; | |
| 4066 return ret; | |
| 4067 } | |
| 4068 if (newsize == 0) { | |
| 4069 MEMENTO_LOCK(); | |
| 4070 do_free(blk, Memento_EventType_realloc); | |
| 4071 MEMENTO_UNLOCK(); | |
| 4072 return NULL; | |
| 4073 } | |
| 4074 | |
| 4075 MEMENTO_LOCK(); | |
| 4076 ret = do_realloc(blk, newsize, Memento_EventType_realloc); | |
| 4077 MEMENTO_UNLOCK(); | |
| 4078 if (!ret) errno = ENOMEM; | |
| 4079 return ret; | |
| 4080 } | |
| 4081 | |
| 4082 int Memento_checkBlock(void *blk) | |
| 4083 { | |
| 4084 Memento_BlkHeader *memblk; | |
| 4085 int ret; | |
| 4086 | |
| 4087 if (blk == NULL) | |
| 4088 return 0; | |
| 4089 | |
| 4090 MEMENTO_LOCK(); | |
| 4091 memblk = MEMBLK_FROMBLK(blk); | |
| 4092 ret = checkBlockUser(memblk, "check"); | |
| 4093 MEMENTO_UNLOCK(); | |
| 4094 return ret; | |
| 4095 } | |
| 4096 | |
| 4097 #ifndef MEMENTO_LEAKONLY | |
| 4098 static int Memento_Internal_checkAllAlloced(Memento_BlkHeader *memblk, void *arg) | |
| 4099 { | |
| 4100 BlkCheckData *data = (BlkCheckData *)arg; | |
| 4101 | |
| 4102 Memento_Internal_checkAllocedBlock(memblk, data); | |
| 4103 if (data->preCorrupt || data->postCorrupt) { | |
| 4104 if ((data->found & 2) == 0) { | |
| 4105 fprintf(stderr, "Allocated blocks:\n"); | |
| 4106 data->found |= 2; | |
| 4107 } | |
| 4108 fprintf(stderr, " Block "); | |
| 4109 showBlock(memblk, ' '); | |
| 4110 if (data->preCorrupt) { | |
| 4111 fprintf(stderr, " Preguard "); | |
| 4112 } | |
| 4113 if (data->postCorrupt) { | |
| 4114 fprintf(stderr, "%s Postguard ", | |
| 4115 (data->preCorrupt ? "&" : "")); | |
| 4116 } | |
| 4117 fprintf(stderr, "corrupted.\n " | |
| 4118 "Block last checked OK at allocation %d. Now %d.\n", | |
| 4119 memblk->lastCheckedOK, memento.sequence); | |
| 4120 if (memento.abortOnCorruption) { | |
| 4121 fprintf(stderr, "*** memblk corrupted, calling abort()\n"); | |
| 4122 abort(); | |
| 4123 } | |
| 4124 data->preCorrupt = 0; | |
| 4125 data->postCorrupt = 0; | |
| 4126 data->freeCorrupt = 0; | |
| 4127 if ((memblk->flags & Memento_Flag_Reported) == 0) | |
| 4128 { | |
| 4129 memblk->flags |= Memento_Flag_Reported; | |
| 4130 data->found |= 8; | |
| 4131 } | |
| 4132 } | |
| 4133 else | |
| 4134 memblk->lastCheckedOK = memento.sequence; | |
| 4135 return 0; | |
| 4136 } | |
| 4137 | |
| 4138 static int Memento_Internal_checkAllFreed(Memento_BlkHeader *memblk, void *arg) | |
| 4139 { | |
| 4140 BlkCheckData *data = (BlkCheckData *)arg; | |
| 4141 | |
| 4142 Memento_Internal_checkFreedBlock(memblk, data); | |
| 4143 if (data->preCorrupt || data->postCorrupt || data->freeCorrupt) { | |
| 4144 if ((data->found & 4) == 0) { | |
| 4145 fprintf(stderr, "Freed blocks:\n"); | |
| 4146 data->found |= 4; | |
| 4147 } | |
| 4148 fprintf(stderr, " "); | |
| 4149 showBlock(memblk, ' '); | |
| 4150 if (data->freeCorrupt) { | |
| 4151 fprintf(stderr, " index %d (address "FMTP") onwards", (int)data->index, | |
| 4152 &((char *)MEMBLK_TOBLK(memblk))[data->index]); | |
| 4153 if (data->preCorrupt) { | |
| 4154 fprintf(stderr, "+ preguard"); | |
| 4155 } | |
| 4156 if (data->postCorrupt) { | |
| 4157 fprintf(stderr, "+ postguard"); | |
| 4158 } | |
| 4159 } else { | |
| 4160 if (data->preCorrupt) { | |
| 4161 fprintf(stderr, " preguard"); | |
| 4162 } | |
| 4163 if (data->postCorrupt) { | |
| 4164 fprintf(stderr, "%s Postguard", | |
| 4165 (data->preCorrupt ? "+" : "")); | |
| 4166 } | |
| 4167 } | |
| 4168 VALGRIND_MAKE_MEM_DEFINED(memblk, sizeof(Memento_BlkHeader)); | |
| 4169 fprintf(stderr, " corrupted.\n" | |
| 4170 " Block last checked OK at allocation %d. Now %d.\n", | |
| 4171 memblk->lastCheckedOK, memento.sequence); | |
| 4172 if ((memblk->flags & Memento_Flag_Reported) == 0) | |
| 4173 { | |
| 4174 memblk->flags |= Memento_Flag_Reported; | |
| 4175 data->found |= 8; | |
| 4176 } | |
| 4177 VALGRIND_MAKE_MEM_NOACCESS(memblk, sizeof(Memento_BlkHeader)); | |
| 4178 data->preCorrupt = 0; | |
| 4179 data->postCorrupt = 0; | |
| 4180 data->freeCorrupt = 0; | |
| 4181 } | |
| 4182 else | |
| 4183 memblk->lastCheckedOK = memento.sequence; | |
| 4184 return 0; | |
| 4185 } | |
| 4186 #endif /* MEMENTO_LEAKONLY */ | |
| 4187 | |
| 4188 static int Memento_checkAllMemoryLocked(void) | |
| 4189 { | |
| 4190 #ifndef MEMENTO_LEAKONLY | |
| 4191 BlkCheckData data; | |
| 4192 | |
| 4193 memset(&data, 0, sizeof(data)); | |
| 4194 Memento_appBlocks(&memento.used, Memento_Internal_checkAllAlloced, &data); | |
| 4195 Memento_appBlocks(&memento.free, Memento_Internal_checkAllFreed, &data); | |
| 4196 return data.found; | |
| 4197 #else | |
| 4198 return 0; | |
| 4199 #endif | |
| 4200 } | |
| 4201 | |
| 4202 int Memento_checkAllMemory(void) | |
| 4203 { | |
| 4204 #ifndef MEMENTO_LEAKONLY | |
| 4205 int ret; | |
| 4206 | |
| 4207 MEMENTO_LOCK(); | |
| 4208 ret = Memento_checkAllMemoryLocked(); | |
| 4209 MEMENTO_UNLOCK(); | |
| 4210 if (ret & 8) { | |
| 4211 Memento_breakpoint(); | |
| 4212 return 1; | |
| 4213 } | |
| 4214 #endif | |
| 4215 return 0; | |
| 4216 } | |
| 4217 | |
| 4218 int Memento_setParanoia(int i) | |
| 4219 { | |
| 4220 memento.paranoia = i; | |
| 4221 if (memento.paranoia > 0) | |
| 4222 memento.countdown = memento.paranoia; | |
| 4223 else | |
| 4224 memento.countdown = -memento.paranoia; | |
| 4225 return i; | |
| 4226 } | |
| 4227 | |
| 4228 int Memento_setIgnoreNewDelete(int ignore) | |
| 4229 { | |
| 4230 int ret = memento.ignoreNewDelete; | |
| 4231 memento.ignoreNewDelete = ignore; | |
| 4232 return ret; | |
| 4233 } | |
| 4234 | |
| 4235 int Memento_paranoidAt(int i) | |
| 4236 { | |
| 4237 memento.paranoidAt = i; | |
| 4238 return i; | |
| 4239 } | |
| 4240 | |
| 4241 int Memento_getBlockNum(void *b) | |
| 4242 { | |
| 4243 Memento_BlkHeader *memblk; | |
| 4244 if (b == NULL) | |
| 4245 return 0; | |
| 4246 memblk = MEMBLK_FROMBLK(b); | |
| 4247 return (memblk->sequence); | |
| 4248 } | |
| 4249 | |
| 4250 int Memento_check(void) | |
| 4251 { | |
| 4252 int result; | |
| 4253 | |
| 4254 fprintf(stderr, "Checking memory\n"); | |
| 4255 result = Memento_checkAllMemory(); | |
| 4256 fprintf(stderr, "Memory checked!\n"); | |
| 4257 return result; | |
| 4258 } | |
| 4259 | |
| 4260 int Memento_find(void *a) | |
| 4261 { | |
| 4262 Memento_BlkHeader *blk; | |
| 4263 int s; | |
| 4264 int flags; | |
| 4265 | |
| 4266 MEMENTO_LOCK(); | |
| 4267 blk = find_enclosing_block(&memento.used, a, &flags); | |
| 4268 if (blk != NULL) { | |
| 4269 fprintf(stderr, "Address "FMTP" is in %sallocated block ", | |
| 4270 a, | |
| 4271 (flags == 1 ? "" : (flags == 2 ? "preguard of " : "postguard of "))); | |
| 4272 s = showBlock(blk, ' '); | |
| 4273 fprintf(stderr, "\n"); | |
| 4274 MEMENTO_UNLOCK(); | |
| 4275 return s; | |
| 4276 } | |
| 4277 blk = find_enclosing_block(&memento.free, a, &flags); | |
| 4278 if (blk != NULL) { | |
| 4279 fprintf(stderr, "Address "FMTP" is in %sfreed block ", | |
| 4280 a, | |
| 4281 (flags == 1 ? "" : (flags == 2 ? "preguard of " : "postguard of "))); | |
| 4282 s = showBlock(blk, ' '); | |
| 4283 fprintf(stderr, "\n"); | |
| 4284 MEMENTO_UNLOCK(); | |
| 4285 return s; | |
| 4286 } | |
| 4287 MEMENTO_UNLOCK(); | |
| 4288 return 0; | |
| 4289 } | |
| 4290 | |
| 4291 void Memento_breakOnFree(void *a) | |
| 4292 { | |
| 4293 Memento_BlkHeader *blk; | |
| 4294 int flags; | |
| 4295 | |
| 4296 MEMENTO_LOCK(); | |
| 4297 blk = find_enclosing_block(&memento.used, a, &flags); | |
| 4298 if (blk != NULL) { | |
| 4299 fprintf(stderr, "Will stop when address "FMTP" (in %sallocated block ", | |
| 4300 a, | |
| 4301 (flags == 1 ? "" : (flags == 2 ? "preguard of " : "postguard of "))); | |
| 4302 showBlock(blk, ' '); | |
| 4303 fprintf(stderr, ") is freed\n"); | |
| 4304 VALGRIND_MAKE_MEM_DEFINED(blk, sizeof(Memento_BlkHeader)); | |
| 4305 blk->flags |= Memento_Flag_BreakOnFree; | |
| 4306 VALGRIND_MAKE_MEM_NOACCESS(blk, sizeof(Memento_BlkHeader)); | |
| 4307 MEMENTO_UNLOCK(); | |
| 4308 return; | |
| 4309 } | |
| 4310 blk = find_enclosing_block(&memento.free, a, &flags); | |
| 4311 if (blk != NULL) { | |
| 4312 fprintf(stderr, "Can't stop on free; address "FMTP" is in %sfreed block ", | |
| 4313 a, | |
| 4314 (flags == 1 ? "" : (flags == 2 ? "preguard of " : "postguard of "))); | |
| 4315 showBlock(blk, ' '); | |
| 4316 fprintf(stderr, "\n"); | |
| 4317 MEMENTO_UNLOCK(); | |
| 4318 return; | |
| 4319 } | |
| 4320 fprintf(stderr, "Can't stop on free; address "FMTP" is not in a known block.\n", a); | |
| 4321 MEMENTO_UNLOCK(); | |
| 4322 } | |
| 4323 | |
| 4324 void Memento_breakOnRealloc(void *a) | |
| 4325 { | |
| 4326 Memento_BlkHeader *blk; | |
| 4327 int flags; | |
| 4328 | |
| 4329 MEMENTO_LOCK(); | |
| 4330 blk = find_enclosing_block(&memento.used, a, &flags); | |
| 4331 if (blk != NULL) { | |
| 4332 fprintf(stderr, "Will stop when address "FMTP" (in %sallocated block ", | |
| 4333 a, | |
| 4334 (flags == 1 ? "" : (flags == 2 ? "preguard of " : "postguard of "))); | |
| 4335 showBlock(blk, ' '); | |
| 4336 fprintf(stderr, ") is freed (or realloced)\n"); | |
| 4337 VALGRIND_MAKE_MEM_DEFINED(blk, sizeof(Memento_BlkHeader)); | |
| 4338 blk->flags |= Memento_Flag_BreakOnFree | Memento_Flag_BreakOnRealloc; | |
| 4339 VALGRIND_MAKE_MEM_NOACCESS(blk, sizeof(Memento_BlkHeader)); | |
| 4340 MEMENTO_UNLOCK(); | |
| 4341 return; | |
| 4342 } | |
| 4343 blk = find_enclosing_block(&memento.free, a, &flags); | |
| 4344 if (blk != NULL) { | |
| 4345 fprintf(stderr, "Can't stop on free/realloc; address "FMTP" is in %sfreed block ", | |
| 4346 a, | |
| 4347 (flags == 1 ? "" : (flags == 2 ? "preguard of " : "postguard of "))); | |
| 4348 showBlock(blk, ' '); | |
| 4349 fprintf(stderr, "\n"); | |
| 4350 MEMENTO_UNLOCK(); | |
| 4351 return; | |
| 4352 } | |
| 4353 fprintf(stderr, "Can't stop on free/realloc; address "FMTP" is not in a known block.\n", a); | |
| 4354 MEMENTO_UNLOCK(); | |
| 4355 } | |
| 4356 | |
| 4357 int Memento_failAt(int i) | |
| 4358 { | |
| 4359 memento.failAt = i; | |
| 4360 if ((memento.sequence > memento.failAt) && | |
| 4361 (memento.failing != 0)) | |
| 4362 Memento_startFailing(); | |
| 4363 return i; | |
| 4364 } | |
| 4365 | |
| 4366 size_t Memento_setMax(size_t max) | |
| 4367 { | |
| 4368 memento.maxMemory = max; | |
| 4369 return max; | |
| 4370 } | |
| 4371 | |
| 4372 void Memento_startLeaking(void) | |
| 4373 { | |
| 4374 if (!memento.inited) | |
| 4375 Memento_init(); | |
| 4376 memento.leaking++; | |
| 4377 } | |
| 4378 | |
| 4379 void Memento_stopLeaking(void) | |
| 4380 { | |
| 4381 memento.leaking--; | |
| 4382 } | |
| 4383 | |
| 4384 int Memento_squeezing(void) | |
| 4385 { | |
| 4386 return memento.squeezing; | |
| 4387 } | |
| 4388 | |
| 4389 int Memento_setVerbose(int x) | |
| 4390 { | |
| 4391 memento.verbose = x; | |
| 4392 return x; | |
| 4393 } | |
| 4394 | |
| 4395 int Memento_addBacktraceLimitFnname(const char *fnname) | |
| 4396 { | |
| 4397 char **ss; | |
| 4398 char *s; | |
| 4399 if (!memento.inited) | |
| 4400 Memento_init(); | |
| 4401 ss = MEMENTO_UNDERLYING_REALLOC( | |
| 4402 memento.backtraceLimitFnnames, | |
| 4403 sizeof(*memento.backtraceLimitFnnames) * (memento.backtraceLimitFnnamesNum + 1) | |
| 4404 ); | |
| 4405 if (!ss) { | |
| 4406 fprintf(stderr, "Memento_addBacktraceLimitFnname(): out of memory\n"); | |
| 4407 return -1; | |
| 4408 } | |
| 4409 memento.backtraceLimitFnnames = ss; | |
| 4410 s = MEMENTO_UNDERLYING_MALLOC(strlen(fnname) + 1); | |
| 4411 if (!s) { | |
| 4412 fprintf(stderr, "Memento_addBacktraceLimitFnname(): out of memory\n"); | |
| 4413 return -1; | |
| 4414 } | |
| 4415 memento.backtraceLimitFnnames[memento.backtraceLimitFnnamesNum] = s; | |
| 4416 strcpy(s, fnname); | |
| 4417 memento.backtraceLimitFnnamesNum += 1; | |
| 4418 return 0; | |
| 4419 } | |
| 4420 | |
| 4421 int Memento_setAtexitFin(int atexitfin) | |
| 4422 { | |
| 4423 if (!memento.inited) { | |
| 4424 Memento_init(); | |
| 4425 } | |
| 4426 memento.atexitFin = atexitfin; | |
| 4427 return 0; | |
| 4428 } | |
| 4429 | |
| 4430 void *Memento_cpp_new(size_t size) | |
| 4431 { | |
| 4432 void *ret; | |
| 4433 | |
| 4434 if (!memento.inited) | |
| 4435 Memento_init(); | |
| 4436 | |
| 4437 if (memento.ignoreNewDelete) | |
| 4438 return MEMENTO_UNDERLYING_MALLOC(size); | |
| 4439 | |
| 4440 if (size == 0) | |
| 4441 size = 1; | |
| 4442 MEMENTO_LOCK(); | |
| 4443 ret = do_malloc(size, Memento_EventType_new); | |
| 4444 MEMENTO_UNLOCK(); | |
| 4445 return ret; | |
| 4446 } | |
| 4447 | |
| 4448 void Memento_cpp_delete(void *pointer) | |
| 4449 { | |
| 4450 if (!pointer) | |
| 4451 return; | |
| 4452 | |
| 4453 if (!memento.inited) | |
| 4454 Memento_init(); | |
| 4455 if (memento.ignoreNewDelete) | |
| 4456 { | |
| 4457 MEMENTO_UNDERLYING_FREE(pointer); | |
| 4458 return; | |
| 4459 } | |
| 4460 | |
| 4461 MEMENTO_LOCK(); | |
| 4462 do_free(pointer, Memento_EventType_delete); | |
| 4463 MEMENTO_UNLOCK(); | |
| 4464 } | |
| 4465 | |
| 4466 /* Some C++ systems (apparently) don't provide new[] or delete[] | |
| 4467 * operators. Provide a way to cope with this */ | |
| 4468 void *Memento_cpp_new_array(size_t size) | |
| 4469 { | |
| 4470 void *ret; | |
| 4471 if (!memento.inited) | |
| 4472 Memento_init(); | |
| 4473 | |
| 4474 if (size == 0) | |
| 4475 size = 1; | |
| 4476 | |
| 4477 if (memento.ignoreNewDelete) | |
| 4478 return MEMENTO_UNDERLYING_MALLOC(size); | |
| 4479 | |
| 4480 MEMENTO_LOCK(); | |
| 4481 ret = do_malloc(size, Memento_EventType_newArray); | |
| 4482 MEMENTO_UNLOCK(); | |
| 4483 return ret; | |
| 4484 } | |
| 4485 | |
| 4486 void Memento_cpp_delete_array(void *pointer) | |
| 4487 { | |
| 4488 if (memento.ignoreNewDelete) | |
| 4489 { | |
| 4490 MEMENTO_UNDERLYING_FREE(pointer); | |
| 4491 return; | |
| 4492 } | |
| 4493 | |
| 4494 MEMENTO_LOCK(); | |
| 4495 do_free(pointer, Memento_EventType_deleteArray); | |
| 4496 MEMENTO_UNLOCK(); | |
| 4497 } | |
| 4498 | |
| 4499 #else /* MEMENTO */ | |
| 4500 | |
| 4501 /* Just in case anyone has left some debugging code in... */ | |
| 4502 void (Memento_breakpoint)(void) | |
| 4503 { | |
| 4504 } | |
| 4505 | |
| 4506 int (Memento_checkBlock)(void *b) | |
| 4507 { | |
| 4508 return 0; | |
| 4509 } | |
| 4510 | |
| 4511 int (Memento_checkAllMemory)(void) | |
| 4512 { | |
| 4513 return 0; | |
| 4514 } | |
| 4515 | |
| 4516 int (Memento_check)(void) | |
| 4517 { | |
| 4518 return 0; | |
| 4519 } | |
| 4520 | |
| 4521 int (Memento_setParanoia)(int i) | |
| 4522 { | |
| 4523 return 0; | |
| 4524 } | |
| 4525 | |
| 4526 int (Memento_paranoidAt)(int i) | |
| 4527 { | |
| 4528 return 0; | |
| 4529 } | |
| 4530 | |
| 4531 int (Memento_breakAt)(int i) | |
| 4532 { | |
| 4533 return 0; | |
| 4534 } | |
| 4535 | |
| 4536 int (Memento_getBlockNum)(void *i) | |
| 4537 { | |
| 4538 return 0; | |
| 4539 } | |
| 4540 | |
| 4541 int (Memento_find)(void *a) | |
| 4542 { | |
| 4543 return 0; | |
| 4544 } | |
| 4545 | |
| 4546 int (Memento_failAt)(int i) | |
| 4547 { | |
| 4548 return 0; | |
| 4549 } | |
| 4550 | |
| 4551 void (Memento_breakOnFree)(void *a) | |
| 4552 { | |
| 4553 } | |
| 4554 | |
| 4555 void (Memento_breakOnRealloc)(void *a) | |
| 4556 { | |
| 4557 } | |
| 4558 | |
| 4559 void *(Memento_takeRef)(void *a) | |
| 4560 { | |
| 4561 return a; | |
| 4562 } | |
| 4563 | |
| 4564 void *(Memento_dropRef)(void *a) | |
| 4565 { | |
| 4566 return a; | |
| 4567 } | |
| 4568 | |
| 4569 void *(Memento_adjustRef)(void *a, int adjust) | |
| 4570 { | |
| 4571 return a; | |
| 4572 } | |
| 4573 | |
| 4574 void *(Memento_reference)(void *a) | |
| 4575 { | |
| 4576 return a; | |
| 4577 } | |
| 4578 | |
| 4579 #undef Memento_malloc | |
| 4580 #undef Memento_free | |
| 4581 #undef Memento_realloc | |
| 4582 #undef Memento_calloc | |
| 4583 #undef Memento_strdup | |
| 4584 #undef Memento_asprintf | |
| 4585 #undef Memento_vasprintf | |
| 4586 | |
| 4587 void *Memento_malloc(size_t size) | |
| 4588 { | |
| 4589 return MEMENTO_UNDERLYING_MALLOC(size); | |
| 4590 } | |
| 4591 | |
| 4592 void Memento_free(void *b) | |
| 4593 { | |
| 4594 MEMENTO_UNDERLYING_FREE(b); | |
| 4595 } | |
| 4596 | |
| 4597 void *Memento_realloc(void *b, size_t s) | |
| 4598 { | |
| 4599 return MEMENTO_UNDERLYING_REALLOC(b, s); | |
| 4600 } | |
| 4601 | |
| 4602 void *Memento_calloc(size_t n, size_t s) | |
| 4603 { | |
| 4604 return MEMENTO_UNDERLYING_CALLOC(n, s); | |
| 4605 } | |
| 4606 | |
| 4607 #if !defined(MEMENTO_GS_HACKS) && !defined(MEMENTO_MUPDF_HACKS) | |
| 4608 /* Avoid calling strdup, in case our compiler doesn't support it. | |
| 4609 * Yes, I'm looking at you, early Visual Studios. */ | |
| 4610 char *Memento_strdup(const char *s) | |
| 4611 { | |
| 4612 size_t len = strlen(s)+1; | |
| 4613 char *ret = MEMENTO_UNDERLYING_MALLOC(len); | |
| 4614 if (ret != NULL) | |
| 4615 memcpy(ret, s, len); | |
| 4616 return ret; | |
| 4617 } | |
| 4618 | |
| 4619 /* Avoid calling asprintf, in case our compiler doesn't support it. | |
| 4620 * Vaguely unhappy about relying on vsnprintf, but... */ | |
| 4621 int Memento_asprintf(char **ret, const char *format, ...) | |
| 4622 { | |
| 4623 va_list va; | |
| 4624 int n; | |
| 4625 int n2; | |
| 4626 | |
| 4627 va_start(va, format); | |
| 4628 n = vsnprintf(NULL, 0, format, va); | |
| 4629 va_end(va); | |
| 4630 if (n < 0) | |
| 4631 return n; | |
| 4632 | |
| 4633 *ret = MEMENTO_UNDERLYING_MALLOC(n+1); | |
| 4634 if (*ret == NULL) | |
| 4635 return -1; | |
| 4636 | |
| 4637 va_start(va, format); | |
| 4638 n2 = vsnprintf(*ret, n + 1, format, va); | |
| 4639 va_end(va); | |
| 4640 | |
| 4641 return n2; | |
| 4642 } | |
| 4643 | |
| 4644 /* Avoid calling vasprintf, in case our compiler doesn't support it. | |
| 4645 * Vaguely unhappy about relying on vsnprintf, but... */ | |
| 4646 int Memento_vasprintf(char **ret, const char *format, va_list ap) | |
| 4647 { | |
| 4648 int n; | |
| 4649 va_list ap2; | |
| 4650 va_copy(ap2, ap); | |
| 4651 | |
| 4652 n = vsnprintf(NULL, 0, format, ap); | |
| 4653 if (n < 0) { | |
| 4654 va_end(ap2); | |
| 4655 return n; | |
| 4656 } | |
| 4657 | |
| 4658 *ret = MEMENTO_UNDERLYING_MALLOC(n+1); | |
| 4659 if (*ret == NULL) { | |
| 4660 va_end(ap2); | |
| 4661 return -1; | |
| 4662 } | |
| 4663 | |
| 4664 n = vsnprintf(*ret, n + 1, format, ap2); | |
| 4665 va_end(ap2); | |
| 4666 | |
| 4667 return n; | |
| 4668 } | |
| 4669 #endif | |
| 4670 | |
| 4671 void (Memento_listBlocks)(void) | |
| 4672 { | |
| 4673 } | |
| 4674 | |
| 4675 void (Memento_listNewBlocks)(void) | |
| 4676 { | |
| 4677 } | |
| 4678 | |
| 4679 void (Memento_listLargeBlocks)(void) | |
| 4680 { | |
| 4681 } | |
| 4682 | |
| 4683 void (Memento_listPhasedBlocks)(void) | |
| 4684 { | |
| 4685 } | |
| 4686 | |
| 4687 int (Memento_setIgnoreNewDelete)(int ignore) | |
| 4688 { | |
| 4689 return 0; | |
| 4690 } | |
| 4691 | |
| 4692 size_t (Memento_setMax)(size_t max) | |
| 4693 { | |
| 4694 return 0; | |
| 4695 } | |
| 4696 | |
| 4697 void (Memento_stats)(void) | |
| 4698 { | |
| 4699 } | |
| 4700 | |
| 4701 void *(Memento_label)(void *ptr, const char *label) | |
| 4702 { | |
| 4703 return ptr; | |
| 4704 } | |
| 4705 | |
| 4706 void (Memento_info)(void *addr) | |
| 4707 { | |
| 4708 } | |
| 4709 | |
| 4710 void (Memento_listBlockInfo)(void) | |
| 4711 { | |
| 4712 } | |
| 4713 | |
| 4714 void (Memento_blockInfo)(void *ptr) | |
| 4715 { | |
| 4716 } | |
| 4717 | |
| 4718 void (Memento_startLeaking)(void) | |
| 4719 { | |
| 4720 } | |
| 4721 | |
| 4722 void (Memento_stopLeaking)(void) | |
| 4723 { | |
| 4724 } | |
| 4725 | |
| 4726 int (Memento_squeezing)(void) | |
| 4727 { | |
| 4728 return 0; | |
| 4729 } | |
| 4730 | |
| 4731 int (Memento_setVerbose)(int x) | |
| 4732 { | |
| 4733 return x; | |
| 4734 } | |
| 4735 | |
| 4736 void Memento_showHash(unsigned int hash) | |
| 4737 { | |
| 4738 } | |
| 4739 | |
| 4740 #endif /* MEMENTO */ | |
| 4741 | |
| 4742 #endif /* MEMENTO_CPP_EXTRAS_ONLY */ | |
| 4743 | |
| 4744 /* Everything here is only for C++, and then only if we haven't | |
| 4745 * disabled it. */ | |
| 4746 | |
| 4747 #ifndef MEMENTO_NO_CPLUSPLUS | |
| 4748 #ifdef __cplusplus | |
| 4749 | |
| 4750 // C++ Operator Veneers - START | |
| 4751 void *operator new(size_t size) | |
| 4752 { | |
| 4753 return Memento_cpp_new(size); | |
| 4754 } | |
| 4755 void operator delete(void *pointer) | |
| 4756 { | |
| 4757 Memento_cpp_delete(pointer); | |
| 4758 } | |
| 4759 void *operator new[](size_t size) | |
| 4760 { | |
| 4761 return Memento_cpp_new_array(size); | |
| 4762 } | |
| 4763 void operator delete[](void *pointer) | |
| 4764 { | |
| 4765 Memento_cpp_delete_array(pointer); | |
| 4766 } | |
| 4767 | |
| 4768 /* Some C++ systems (apparently) don't provide new[] or delete[] | |
| 4769 * operators. Provide a way to cope with this */ | |
| 4770 #ifndef MEMENTO_CPP_NO_ARRAY_CONSTRUCTORS | |
| 4771 void *operator new[](size_t size) | |
| 4772 { | |
| 4773 return Memento_cpp_new_array(size); | |
| 4774 } | |
| 4775 | |
| 4776 void operator delete[](void *pointer) | |
| 4777 { | |
| 4778 Memento_cpp_delete_array(pointer); | |
| 4779 } | |
| 4780 #endif /* MEMENTO_CPP_NO_ARRAY_CONSTRUCTORS */ | |
| 4781 // C++ Operator Veneers - END | |
| 4782 | |
| 4783 #endif /* __cplusplus */ | |
| 4784 #endif /* MEMENTO_NO_CPLUSPLUS */ |
