]>
Commit | Line | Data |
---|---|---|
5113680f | 1 | /* |
552cc11b | 2 | * Copyright (C) 2006-2008 Martin Willi |
5113680f MW |
3 | * Hochschule fuer Technik Rapperswil |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify it | |
6 | * under the terms of the GNU General Public License as published by the | |
7 | * Free Software Foundation; either version 2 of the License, or (at your | |
8 | * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. | |
9 | * | |
10 | * This program is distributed in the hope that it will be useful, but | |
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |
12 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
13 | * for more details. | |
14 | */ | |
7daf5226 | 15 | |
7a485e90 MW |
16 | #define _GNU_SOURCE |
17 | #include <sched.h> | |
5113680f | 18 | #include <stddef.h> |
5113680f MW |
19 | #include <string.h> |
20 | #include <stdio.h> | |
21 | #include <malloc.h> | |
7daf5226 | 22 | #include <signal.h> |
5113680f MW |
23 | #include <sys/socket.h> |
24 | #include <netinet/in.h> | |
25 | #include <arpa/inet.h> | |
1d025fbc | 26 | #include <unistd.h> |
8bc96e08 | 27 | #include <syslog.h> |
8bc96e08 | 28 | #include <pthread.h> |
b1904247 | 29 | #include <netdb.h> |
552cc11b | 30 | #include <locale.h> |
5113680f MW |
31 | |
32 | #include "leak_detective.h" | |
33 | ||
60356f33 | 34 | #include <library.h> |
db7ef624 | 35 | #include <debug.h> |
f7237cf3 | 36 | #include <utils/backtrace.h> |
fce3b5c3 | 37 | #include <utils/hashtable.h> |
5113680f | 38 | |
552cc11b MW |
39 | typedef struct private_leak_detective_t private_leak_detective_t; |
40 | ||
41 | /** | |
42 | * private data of leak_detective | |
43 | */ | |
44 | struct private_leak_detective_t { | |
45 | ||
46 | /** | |
47 | * public functions | |
48 | */ | |
49 | leak_detective_t public; | |
50 | }; | |
5113680f MW |
51 | |
52 | /** | |
269f7f44 | 53 | * Magic value which helps to detect memory corruption. Yummy! |
5113680f | 54 | */ |
269f7f44 MW |
55 | #define MEMORY_HEADER_MAGIC 0x7ac0be11 |
56 | ||
b7ef3f62 MW |
57 | /** |
58 | * Magic written to tail of allocation | |
59 | */ | |
60 | #define MEMORY_TAIL_MAGIC 0xcafebabe | |
61 | ||
269f7f44 MW |
62 | /** |
63 | * Pattern which is filled in memory before freeing it | |
64 | */ | |
65 | #define MEMORY_FREE_PATTERN 0xFF | |
66 | ||
67 | /** | |
68 | * Pattern which is filled in newly allocated memory | |
69 | */ | |
70 | #define MEMORY_ALLOC_PATTERN 0xEE | |
71 | ||
5113680f | 72 | |
5113680f MW |
73 | static void install_hooks(void); |
74 | static void uninstall_hooks(void); | |
75 | static void *malloc_hook(size_t, const void *); | |
76 | static void *realloc_hook(void *, size_t, const void *); | |
77 | static void free_hook(void*, const void *); | |
73760ca5 | 78 | |
cce97b64 MW |
79 | void *(*old_malloc_hook)(size_t, const void *); |
80 | void *(*old_realloc_hook)(void *, size_t, const void *); | |
81 | void (*old_free_hook)(void*, const void *); | |
82 | ||
73760ca5 MW |
83 | static u_int count_malloc = 0; |
84 | static u_int count_free = 0; | |
85 | static u_int count_realloc = 0; | |
5113680f MW |
86 | |
87 | typedef struct memory_header_t memory_header_t; | |
b7ef3f62 | 88 | typedef struct memory_tail_t memory_tail_t; |
5113680f MW |
89 | |
90 | /** | |
91 | * Header which is prepended to each allocated memory block | |
92 | */ | |
93 | struct memory_header_t { | |
7daf5226 | 94 | |
5113680f MW |
95 | /** |
96 | * Number of bytes following after the header | |
97 | */ | |
b7ef3f62 | 98 | u_int bytes; |
7daf5226 | 99 | |
5113680f MW |
100 | /** |
101 | * Pointer to previous entry in linked list | |
102 | */ | |
103 | memory_header_t *previous; | |
7daf5226 | 104 | |
5113680f MW |
105 | /** |
106 | * Pointer to next entry in linked list | |
107 | */ | |
108 | memory_header_t *next; | |
7daf5226 | 109 | |
f7237cf3 MW |
110 | /** |
111 | * backtrace taken during (re-)allocation | |
112 | */ | |
113 | backtrace_t *backtrace; | |
7daf5226 | 114 | |
b7ef3f62 MW |
115 | /** |
116 | * magic bytes to detect bad free or heap underflow, MEMORY_HEADER_MAGIC | |
117 | */ | |
118 | u_int32_t magic; | |
7daf5226 | 119 | |
b7ef3f62 MW |
120 | }__attribute__((__packed__)); |
121 | ||
122 | /** | |
123 | * tail appended to each allocated memory block | |
124 | */ | |
125 | struct memory_tail_t { | |
126 | ||
127 | /** | |
128 | * Magic bytes to detect heap overflow, MEMORY_TAIL_MAGIC | |
129 | */ | |
130 | u_int32_t magic; | |
7daf5226 | 131 | |
b7ef3f62 | 132 | }__attribute__((__packed__)); |
5113680f MW |
133 | |
134 | /** | |
7daf5226 | 135 | * first mem header is just a dummy to chain |
5113680f MW |
136 | * the others on it... |
137 | */ | |
6b3292da | 138 | static memory_header_t first_header = { |
5113680f MW |
139 | magic: MEMORY_HEADER_MAGIC, |
140 | bytes: 0, | |
f7237cf3 | 141 | backtrace: NULL, |
5113680f MW |
142 | previous: NULL, |
143 | next: NULL | |
144 | }; | |
145 | ||
1d025fbc | 146 | /** |
7daf5226 | 147 | * are the hooks currently installed? |
1d025fbc | 148 | */ |
6b3292da | 149 | static bool installed = FALSE; |
5113680f | 150 | |
986d23bd | 151 | /** |
552cc11b | 152 | * Leak report white list |
151168f6 | 153 | * |
552cc11b | 154 | * List of functions using static allocation buffers or should be suppressed |
7daf5226 | 155 | * otherwise on leak report. |
986d23bd | 156 | */ |
552cc11b | 157 | char *whitelist[] = { |
f7237cf3 MW |
158 | /* backtraces, including own */ |
159 | "backtrace_create", | |
7939864d | 160 | /* pthread stuff */ |
552cc11b MW |
161 | "pthread_create", |
162 | "pthread_setspecific", | |
9eb85cff | 163 | "__pthread_setspecific", |
7939864d | 164 | /* glibc functions */ |
552cc11b | 165 | "mktime", |
e69f33f6 | 166 | "__gmtime_r", |
c198fc55 | 167 | "localtime_r", |
552cc11b | 168 | "tzset", |
07bda3fe | 169 | "time_printf_hook", |
552cc11b MW |
170 | "inet_ntoa", |
171 | "strerror", | |
0ffedbfb | 172 | "getprotobyname", |
552cc11b MW |
173 | "getprotobynumber", |
174 | "getservbyport", | |
175 | "getservbyname", | |
3f9ec06f | 176 | "gethostbyname2", |
5a22a021 MW |
177 | "gethostbyname_r", |
178 | "gethostbyname2_r", | |
3f9ec06f | 179 | "getnetbyname", |
25b12c69 MW |
180 | "getpwnam_r", |
181 | "getgrnam_r", | |
552cc11b | 182 | "register_printf_function", |
86813bef | 183 | "register_printf_specifier", |
552cc11b MW |
184 | "syslog", |
185 | "vsyslog", | |
044e0dd1 MW |
186 | "__syslog_chk", |
187 | "__vsyslog_chk", | |
552cc11b MW |
188 | "getaddrinfo", |
189 | "setlocale", | |
70789d28 | 190 | "getpass", |
7939864d MW |
191 | /* ignore dlopen, as we do not dlclose to get proper leak reports */ |
192 | "dlopen", | |
a3d92a37 | 193 | "dlerror", |
1caa265c | 194 | "dlclose", |
07bda3fe | 195 | "dlsym", |
7939864d | 196 | /* mysql functions */ |
552cc11b MW |
197 | "mysql_init_character_set", |
198 | "init_client_errs", | |
199 | "my_thread_init", | |
7939864d | 200 | /* fastcgi library */ |
cf4caefa | 201 | "FCGX_Init", |
7939864d MW |
202 | /* libxml */ |
203 | "xmlInitCharEncodingHandlers", | |
204 | "xmlInitParser", | |
205 | "xmlInitParserCtxt", | |
727b0f11 AS |
206 | /* libcurl */ |
207 | "Curl_client_write", | |
7939864d MW |
208 | /* ClearSilver */ |
209 | "nerr_init", | |
915e04b2 MW |
210 | /* OpenSSL */ |
211 | "RSA_new_method", | |
212 | "DH_new_method", | |
fe5d7c43 | 213 | "ENGINE_load_builtin_engines", |
04425625 | 214 | "OPENSSL_config", |
85fd609e | 215 | "ecdsa_check", |
40b2be16 | 216 | "ERR_put_error", |
513a1a28 MW |
217 | /* libgcrypt */ |
218 | "gcry_control", | |
219 | "gcry_check_version", | |
a41d0932 MW |
220 | "gcry_randomize", |
221 | "gcry_create_nonce", | |
50a9e845 MW |
222 | /* NSPR */ |
223 | "PR_CallOnce", | |
1888dd6b AS |
224 | /* libapr */ |
225 | "apr_pool_create_ex", | |
ec8426a3 MW |
226 | /* glib */ |
227 | "g_type_init_with_debug_flags", | |
228 | "g_type_register_static", | |
229 | "g_type_class_ref", | |
230 | "g_type_create_instance", | |
231 | "g_type_add_interface_static", | |
232 | "g_type_interface_add_prerequisite", | |
233 | "g_socket_connection_factory_lookup_type", | |
234 | /* libgpg */ | |
235 | "gpg_err_init", | |
7cfa84f5 MW |
236 | /* gnutls */ |
237 | "gnutls_global_init", | |
986d23bd MW |
238 | }; |
239 | ||
42e0f26e MW |
240 | METHOD(leak_detective_t, report, void, |
241 | private_leak_detective_t *this, bool detailed) | |
6b3292da | 242 | { |
091d1780 | 243 | if (lib->leak_detective) |
6b3292da | 244 | { |
091d1780 MW |
245 | memory_header_t *hdr; |
246 | int leaks = 0, whitelisted = 0; | |
247 | ||
248 | for (hdr = first_header.next; hdr != NULL; hdr = hdr->next) | |
cf4caefa | 249 | { |
b94feb4b MW |
250 | if (hdr->backtrace->contains_function(hdr->backtrace, |
251 | whitelist, countof(whitelist))) | |
091d1780 MW |
252 | { |
253 | whitelisted++; | |
254 | } | |
255 | else | |
256 | { | |
257 | fprintf(stderr, "Leak (%d bytes at %p):\n", hdr->bytes, hdr + 1); | |
258 | /* skip the first frame, contains leak detective logic */ | |
259 | hdr->backtrace->log(hdr->backtrace, stderr, detailed); | |
260 | leaks++; | |
261 | } | |
cf4caefa | 262 | } |
091d1780 | 263 | switch (leaks) |
986d23bd | 264 | { |
091d1780 MW |
265 | case 0: |
266 | fprintf(stderr, "No leaks detected"); | |
267 | break; | |
268 | case 1: | |
269 | fprintf(stderr, "One leak detected"); | |
270 | break; | |
271 | default: | |
272 | fprintf(stderr, "%d leaks detected", leaks); | |
273 | break; | |
986d23bd | 274 | } |
091d1780 | 275 | fprintf(stderr, ", %d suppressed by whitelist\n", whitelisted); |
6b3292da | 276 | } |
091d1780 | 277 | else |
6b3292da | 278 | { |
091d1780 | 279 | fprintf(stderr, "Leak detective disabled\n"); |
6b3292da MW |
280 | } |
281 | } | |
282 | ||
5113680f MW |
283 | /** |
284 | * Installs the malloc hooks, enables leak detection | |
285 | */ | |
6b3292da | 286 | static void install_hooks() |
5113680f | 287 | { |
8bc96e08 MW |
288 | if (!installed) |
289 | { | |
290 | old_malloc_hook = __malloc_hook; | |
291 | old_realloc_hook = __realloc_hook; | |
292 | old_free_hook = __free_hook; | |
293 | __malloc_hook = malloc_hook; | |
294 | __realloc_hook = realloc_hook; | |
295 | __free_hook = free_hook; | |
296 | installed = TRUE; | |
297 | } | |
5113680f MW |
298 | } |
299 | ||
300 | /** | |
301 | * Uninstalls the malloc hooks, disables leak detection | |
302 | */ | |
6b3292da | 303 | static void uninstall_hooks() |
5113680f | 304 | { |
8bc96e08 MW |
305 | if (installed) |
306 | { | |
307 | __malloc_hook = old_malloc_hook; | |
308 | __free_hook = old_free_hook; | |
309 | __realloc_hook = old_realloc_hook; | |
310 | installed = FALSE; | |
311 | } | |
5113680f MW |
312 | } |
313 | ||
fce3b5c3 MW |
314 | /** |
315 | * Hashtable hash function | |
316 | */ | |
317 | static u_int hash(backtrace_t *key) | |
318 | { | |
319 | enumerator_t *enumerator; | |
320 | void *addr; | |
321 | u_int hash = 0; | |
322 | ||
323 | enumerator = key->create_frame_enumerator(key); | |
324 | while (enumerator->enumerate(enumerator, &addr)) | |
325 | { | |
326 | hash = chunk_hash_inc(chunk_from_thing(addr), hash); | |
327 | } | |
328 | enumerator->destroy(enumerator); | |
329 | ||
330 | return hash; | |
331 | } | |
332 | ||
333 | /** | |
334 | * Hashtable equals function | |
335 | */ | |
336 | static bool equals(backtrace_t *a, backtrace_t *b) | |
337 | { | |
338 | return a->equals(a, b); | |
339 | } | |
340 | ||
341 | METHOD(leak_detective_t, usage, void, | |
342 | private_leak_detective_t *this, FILE *out) | |
343 | { | |
344 | int oldpolicy, thresh; | |
345 | pthread_t thread_id = pthread_self(); | |
346 | struct sched_param oldparams, params; | |
347 | memory_header_t *hdr; | |
348 | enumerator_t *enumerator; | |
349 | hashtable_t *entries; | |
350 | struct { | |
351 | /** associated backtrace */ | |
352 | backtrace_t *backtrace; | |
353 | /** total size of all allocations */ | |
354 | size_t bytes; | |
355 | /** number of allocations */ | |
356 | u_int count; | |
357 | } *entry; | |
358 | ||
359 | thresh = lib->settings->get_int(lib->settings, | |
360 | "libstrongswan.leak_detective.usage_threshold", 10240); | |
361 | ||
362 | pthread_getschedparam(thread_id, &oldpolicy, &oldparams); | |
363 | params.__sched_priority = sched_get_priority_max(SCHED_FIFO); | |
364 | pthread_setschedparam(thread_id, SCHED_FIFO, ¶ms); | |
365 | uninstall_hooks(); | |
366 | ||
367 | entries = hashtable_create((hashtable_hash_t)hash, | |
368 | (hashtable_equals_t)equals, 1024); | |
369 | ||
370 | for (hdr = first_header.next; hdr != NULL; hdr = hdr->next) | |
371 | { | |
372 | entry = entries->get(entries, hdr->backtrace); | |
373 | if (entry) | |
374 | { | |
375 | entry->bytes += hdr->bytes; | |
376 | entry->count++; | |
377 | } | |
378 | else | |
379 | { | |
380 | INIT(entry, | |
381 | .backtrace = hdr->backtrace, | |
382 | .bytes = hdr->bytes, | |
383 | .count = 1, | |
384 | ); | |
385 | entries->put(entries, hdr->backtrace, entry); | |
386 | } | |
387 | } | |
388 | enumerator = entries->create_enumerator(entries); | |
389 | while (enumerator->enumerate(enumerator, NULL, &entry)) | |
390 | { | |
391 | if (entry->bytes >= thresh) | |
392 | { | |
393 | fprintf(out, "%d bytes total, %d allocations, %d bytes average:\n", | |
394 | entry->bytes, entry->count, entry->bytes / entry->count); | |
395 | entry->backtrace->log(entry->backtrace, out, TRUE); | |
396 | } | |
397 | free(entry); | |
398 | } | |
399 | enumerator->destroy(enumerator); | |
400 | entries->destroy(entries); | |
401 | ||
402 | install_hooks(); | |
403 | pthread_setschedparam(thread_id, oldpolicy, &oldparams); | |
404 | } | |
405 | ||
5113680f MW |
406 | /** |
407 | * Hook function for malloc() | |
408 | */ | |
6b3292da | 409 | void *malloc_hook(size_t bytes, const void *caller) |
5113680f MW |
410 | { |
411 | memory_header_t *hdr; | |
b7ef3f62 | 412 | memory_tail_t *tail; |
84b18d5f | 413 | pthread_t thread_id = pthread_self(); |
323f9f99 MW |
414 | int oldpolicy; |
415 | struct sched_param oldparams, params; | |
7daf5226 | 416 | |
323f9f99 | 417 | pthread_getschedparam(thread_id, &oldpolicy, &oldparams); |
7daf5226 | 418 | |
323f9f99 | 419 | params.__sched_priority = sched_get_priority_max(SCHED_FIFO); |
84b18d5f | 420 | pthread_setschedparam(thread_id, SCHED_FIFO, ¶ms); |
7daf5226 | 421 | |
73760ca5 | 422 | count_malloc++; |
5113680f | 423 | uninstall_hooks(); |
b7ef3f62 MW |
424 | hdr = malloc(sizeof(memory_header_t) + bytes + sizeof(memory_tail_t)); |
425 | tail = ((void*)hdr) + bytes + sizeof(memory_header_t); | |
986d23bd | 426 | /* set to something which causes crashes */ |
b7ef3f62 MW |
427 | memset(hdr, MEMORY_ALLOC_PATTERN, |
428 | sizeof(memory_header_t) + bytes + sizeof(memory_tail_t)); | |
7daf5226 | 429 | |
5113680f MW |
430 | hdr->magic = MEMORY_HEADER_MAGIC; |
431 | hdr->bytes = bytes; | |
f7237cf3 | 432 | hdr->backtrace = backtrace_create(3); |
b7ef3f62 | 433 | tail->magic = MEMORY_TAIL_MAGIC; |
269f7f44 | 434 | install_hooks(); |
7daf5226 | 435 | |
5113680f MW |
436 | /* insert at the beginning of the list */ |
437 | hdr->next = first_header.next; | |
438 | if (hdr->next) | |
439 | { | |
440 | hdr->next->previous = hdr; | |
441 | } | |
442 | hdr->previous = &first_header; | |
443 | first_header.next = hdr; | |
7daf5226 | 444 | |
84b18d5f | 445 | pthread_setschedparam(thread_id, oldpolicy, &oldparams); |
7daf5226 | 446 | |
5113680f MW |
447 | return hdr + 1; |
448 | } | |
449 | ||
450 | /** | |
451 | * Hook function for free() | |
452 | */ | |
6b3292da | 453 | void free_hook(void *ptr, const void *caller) |
5113680f | 454 | { |
587ebae7 | 455 | memory_header_t *hdr, *current; |
b7ef3f62 | 456 | memory_tail_t *tail; |
323f9f99 | 457 | backtrace_t *backtrace; |
84b18d5f | 458 | pthread_t thread_id = pthread_self(); |
323f9f99 MW |
459 | int oldpolicy; |
460 | struct sched_param oldparams, params; | |
587ebae7 | 461 | bool found = FALSE; |
7daf5226 | 462 | |
5113680f MW |
463 | /* allow freeing of NULL */ |
464 | if (ptr == NULL) | |
465 | { | |
466 | return; | |
467 | } | |
b7ef3f62 MW |
468 | hdr = ptr - sizeof(memory_header_t); |
469 | tail = ptr + hdr->bytes; | |
7daf5226 | 470 | |
84b18d5f | 471 | pthread_getschedparam(thread_id, &oldpolicy, &oldparams); |
7daf5226 | 472 | |
323f9f99 | 473 | params.__sched_priority = sched_get_priority_max(SCHED_FIFO); |
84b18d5f | 474 | pthread_setschedparam(thread_id, SCHED_FIFO, ¶ms); |
7daf5226 | 475 | |
73760ca5 | 476 | count_free++; |
269f7f44 | 477 | uninstall_hooks(); |
6c45e622 MW |
478 | if (hdr->magic != MEMORY_HEADER_MAGIC || |
479 | tail->magic != MEMORY_TAIL_MAGIC) | |
5113680f | 480 | { |
587ebae7 MW |
481 | for (current = &first_header; current != NULL; current = current->next) |
482 | { | |
483 | if (current == hdr) | |
484 | { | |
485 | found = TRUE; | |
486 | break; | |
487 | } | |
488 | } | |
489 | if (found) | |
490 | { | |
491 | /* memory was allocated by our hooks but is corrupted */ | |
492 | fprintf(stderr, "freeing corrupted memory (%p): " | |
493 | "header magic 0x%x, tail magic 0x%x:\n", | |
494 | ptr, hdr->magic, tail->magic); | |
495 | } | |
496 | else | |
497 | { | |
498 | /* memory was not allocated by our hooks */ | |
499 | fprintf(stderr, "freeing invalid memory (%p)", ptr); | |
500 | } | |
f7237cf3 | 501 | backtrace = backtrace_create(3); |
091d1780 | 502 | backtrace->log(backtrace, stderr, TRUE); |
f7237cf3 | 503 | backtrace->destroy(backtrace); |
5113680f | 504 | } |
6c45e622 | 505 | else |
b7ef3f62 | 506 | { |
6c45e622 MW |
507 | /* remove item from list */ |
508 | if (hdr->next) | |
509 | { | |
510 | hdr->next->previous = hdr->previous; | |
511 | } | |
512 | hdr->previous->next = hdr->next; | |
f7237cf3 | 513 | hdr->backtrace->destroy(hdr->backtrace); |
7daf5226 | 514 | |
6c45e622 | 515 | /* clear MAGIC, set mem to something remarkable */ |
587ebae7 MW |
516 | memset(hdr, MEMORY_FREE_PATTERN, |
517 | sizeof(memory_header_t) + hdr->bytes + sizeof(memory_tail_t)); | |
7daf5226 | 518 | |
6c45e622 MW |
519 | free(hdr); |
520 | } | |
7daf5226 | 521 | |
5113680f | 522 | install_hooks(); |
6c90949f | 523 | pthread_setschedparam(thread_id, oldpolicy, &oldparams); |
5113680f MW |
524 | } |
525 | ||
526 | /** | |
527 | * Hook function for realloc() | |
528 | */ | |
6b3292da | 529 | void *realloc_hook(void *old, size_t bytes, const void *caller) |
5113680f | 530 | { |
a401efd0 | 531 | memory_header_t *hdr; |
b7ef3f62 | 532 | memory_tail_t *tail; |
f7237cf3 | 533 | backtrace_t *backtrace; |
84b18d5f | 534 | pthread_t thread_id = pthread_self(); |
323f9f99 MW |
535 | int oldpolicy; |
536 | struct sched_param oldparams, params; | |
7daf5226 | 537 | |
5113680f MW |
538 | /* allow reallocation of NULL */ |
539 | if (old == NULL) | |
540 | { | |
541 | return malloc_hook(bytes, caller); | |
542 | } | |
7daf5226 | 543 | |
a401efd0 | 544 | hdr = old - sizeof(memory_header_t); |
b7ef3f62 | 545 | tail = old + hdr->bytes; |
7daf5226 | 546 | |
84b18d5f | 547 | pthread_getschedparam(thread_id, &oldpolicy, &oldparams); |
7daf5226 | 548 | |
84b18d5f TB |
549 | params.__sched_priority = sched_get_priority_max(SCHED_FIFO); |
550 | pthread_setschedparam(thread_id, SCHED_FIFO, ¶ms); | |
7daf5226 | 551 | |
73760ca5 | 552 | count_realloc++; |
a401efd0 | 553 | uninstall_hooks(); |
6c45e622 MW |
554 | if (hdr->magic != MEMORY_HEADER_MAGIC || |
555 | tail->magic != MEMORY_TAIL_MAGIC) | |
b7ef3f62 | 556 | { |
6c45e622 MW |
557 | fprintf(stderr, "reallocating invalid memory (%p): " |
558 | "header magic 0x%x, tail magic 0x%x:\n", | |
559 | old, hdr->magic, tail->magic); | |
f7237cf3 | 560 | backtrace = backtrace_create(3); |
091d1780 | 561 | backtrace->log(backtrace, stderr, TRUE); |
f7237cf3 | 562 | backtrace->destroy(backtrace); |
b7ef3f62 MW |
563 | } |
564 | /* clear tail magic, allocate, set tail magic */ | |
565 | memset(&tail->magic, MEMORY_ALLOC_PATTERN, sizeof(tail->magic)); | |
566 | hdr = realloc(hdr, sizeof(memory_header_t) + bytes + sizeof(memory_tail_t)); | |
567 | tail = ((void*)hdr) + bytes + sizeof(memory_header_t); | |
568 | tail->magic = MEMORY_TAIL_MAGIC; | |
6c45e622 | 569 | |
a401efd0 MW |
570 | /* update statistics */ |
571 | hdr->bytes = bytes; | |
f7237cf3 MW |
572 | hdr->backtrace->destroy(hdr->backtrace); |
573 | hdr->backtrace = backtrace_create(3); | |
6c45e622 | 574 | |
a401efd0 MW |
575 | /* update header of linked list neighbours */ |
576 | if (hdr->next) | |
577 | { | |
578 | hdr->next->previous = hdr; | |
579 | } | |
580 | hdr->previous->next = hdr; | |
581 | install_hooks(); | |
84b18d5f | 582 | pthread_setschedparam(thread_id, oldpolicy, &oldparams); |
a401efd0 | 583 | return hdr + 1; |
5113680f MW |
584 | } |
585 | ||
42e0f26e MW |
586 | METHOD(leak_detective_t, destroy, void, |
587 | private_leak_detective_t *this) | |
5113680f | 588 | { |
552cc11b | 589 | if (installed) |
9cc7a297 MW |
590 | { |
591 | uninstall_hooks(); | |
9cc7a297 | 592 | } |
552cc11b | 593 | free(this); |
6b3292da MW |
594 | } |
595 | ||
552cc11b MW |
596 | /* |
597 | * see header file | |
73760ca5 | 598 | */ |
552cc11b | 599 | leak_detective_t *leak_detective_create() |
73760ca5 | 600 | { |
42e0f26e MW |
601 | private_leak_detective_t *this; |
602 | ||
603 | INIT(this, | |
604 | .public = { | |
605 | .report = _report, | |
fce3b5c3 | 606 | .usage = _usage, |
42e0f26e MW |
607 | .destroy = _destroy, |
608 | }, | |
609 | ); | |
7daf5226 | 610 | |
552cc11b | 611 | if (getenv("LEAK_DETECTIVE_DISABLE") == NULL) |
73760ca5 | 612 | { |
7a485e90 | 613 | cpu_set_t mask; |
7daf5226 | 614 | |
7a485e90 MW |
615 | CPU_ZERO(&mask); |
616 | CPU_SET(0, &mask); | |
7daf5226 | 617 | |
7a485e90 MW |
618 | if (sched_setaffinity(0, sizeof(cpu_set_t), &mask) != 0) |
619 | { | |
620 | fprintf(stderr, "setting CPU affinity failed: %m"); | |
621 | } | |
7daf5226 | 622 | |
552cc11b | 623 | install_hooks(); |
73760ca5 | 624 | } |
552cc11b | 625 | return &this->public; |
73760ca5 MW |
626 | } |
627 |