]>
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> |
f05b4272 | 35 | #include <utils/debug.h> |
f7237cf3 | 36 | #include <utils/backtrace.h> |
12642a68 | 37 | #include <collections/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 | * Pointer to previous entry in linked list | |
97 | */ | |
98 | memory_header_t *previous; | |
7daf5226 | 99 | |
5113680f MW |
100 | /** |
101 | * Pointer to next entry in linked list | |
102 | */ | |
103 | memory_header_t *next; | |
7daf5226 | 104 | |
f7237cf3 MW |
105 | /** |
106 | * backtrace taken during (re-)allocation | |
107 | */ | |
108 | backtrace_t *backtrace; | |
7daf5226 | 109 | |
35c93479 MW |
110 | /** |
111 | * Number of bytes following after the header | |
112 | */ | |
113 | u_int32_t bytes; | |
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 | |
eb4f4551 MW |
151 | /** |
152 | * Installs the malloc hooks, enables leak detection | |
153 | */ | |
154 | static void install_hooks() | |
155 | { | |
156 | if (!installed) | |
157 | { | |
158 | old_malloc_hook = __malloc_hook; | |
159 | old_realloc_hook = __realloc_hook; | |
160 | old_free_hook = __free_hook; | |
161 | __malloc_hook = malloc_hook; | |
162 | __realloc_hook = realloc_hook; | |
163 | __free_hook = free_hook; | |
164 | installed = TRUE; | |
165 | } | |
166 | } | |
167 | ||
168 | /** | |
169 | * Uninstalls the malloc hooks, disables leak detection | |
170 | */ | |
171 | static void uninstall_hooks() | |
172 | { | |
173 | if (installed) | |
174 | { | |
175 | __malloc_hook = old_malloc_hook; | |
176 | __free_hook = old_free_hook; | |
177 | __realloc_hook = old_realloc_hook; | |
178 | installed = FALSE; | |
179 | } | |
180 | } | |
181 | ||
986d23bd | 182 | /** |
552cc11b | 183 | * Leak report white list |
151168f6 | 184 | * |
552cc11b | 185 | * List of functions using static allocation buffers or should be suppressed |
7daf5226 | 186 | * otherwise on leak report. |
986d23bd | 187 | */ |
552cc11b | 188 | char *whitelist[] = { |
f7237cf3 MW |
189 | /* backtraces, including own */ |
190 | "backtrace_create", | |
7c8b9fcb | 191 | "safe_strerror", |
7939864d | 192 | /* pthread stuff */ |
552cc11b MW |
193 | "pthread_create", |
194 | "pthread_setspecific", | |
9eb85cff | 195 | "__pthread_setspecific", |
7939864d | 196 | /* glibc functions */ |
552cc11b | 197 | "mktime", |
4002b41b | 198 | "ctime", |
e69f33f6 | 199 | "__gmtime_r", |
c198fc55 | 200 | "localtime_r", |
552cc11b | 201 | "tzset", |
07bda3fe | 202 | "time_printf_hook", |
552cc11b MW |
203 | "inet_ntoa", |
204 | "strerror", | |
0ffedbfb | 205 | "getprotobyname", |
552cc11b MW |
206 | "getprotobynumber", |
207 | "getservbyport", | |
208 | "getservbyname", | |
b97ca14d | 209 | "gethostbyname", |
3f9ec06f | 210 | "gethostbyname2", |
5a22a021 MW |
211 | "gethostbyname_r", |
212 | "gethostbyname2_r", | |
3f9ec06f | 213 | "getnetbyname", |
25b12c69 MW |
214 | "getpwnam_r", |
215 | "getgrnam_r", | |
552cc11b | 216 | "register_printf_function", |
86813bef | 217 | "register_printf_specifier", |
552cc11b MW |
218 | "syslog", |
219 | "vsyslog", | |
044e0dd1 MW |
220 | "__syslog_chk", |
221 | "__vsyslog_chk", | |
552cc11b MW |
222 | "getaddrinfo", |
223 | "setlocale", | |
70789d28 | 224 | "getpass", |
b97ca14d AS |
225 | "getpwent_r", |
226 | "setpwent", | |
227 | "endpwent", | |
0bac49b0 | 228 | "getspnam_r", |
7939864d MW |
229 | /* ignore dlopen, as we do not dlclose to get proper leak reports */ |
230 | "dlopen", | |
a3d92a37 | 231 | "dlerror", |
1caa265c | 232 | "dlclose", |
07bda3fe | 233 | "dlsym", |
7939864d | 234 | /* mysql functions */ |
552cc11b MW |
235 | "mysql_init_character_set", |
236 | "init_client_errs", | |
237 | "my_thread_init", | |
7939864d | 238 | /* fastcgi library */ |
cf4caefa | 239 | "FCGX_Init", |
7939864d MW |
240 | /* libxml */ |
241 | "xmlInitCharEncodingHandlers", | |
242 | "xmlInitParser", | |
243 | "xmlInitParserCtxt", | |
727b0f11 AS |
244 | /* libcurl */ |
245 | "Curl_client_write", | |
7939864d MW |
246 | /* ClearSilver */ |
247 | "nerr_init", | |
915e04b2 MW |
248 | /* OpenSSL */ |
249 | "RSA_new_method", | |
250 | "DH_new_method", | |
fe5d7c43 | 251 | "ENGINE_load_builtin_engines", |
04425625 | 252 | "OPENSSL_config", |
85fd609e | 253 | "ecdsa_check", |
40b2be16 | 254 | "ERR_put_error", |
513a1a28 MW |
255 | /* libgcrypt */ |
256 | "gcry_control", | |
257 | "gcry_check_version", | |
a41d0932 MW |
258 | "gcry_randomize", |
259 | "gcry_create_nonce", | |
50a9e845 MW |
260 | /* NSPR */ |
261 | "PR_CallOnce", | |
1888dd6b AS |
262 | /* libapr */ |
263 | "apr_pool_create_ex", | |
ec8426a3 MW |
264 | /* glib */ |
265 | "g_type_init_with_debug_flags", | |
266 | "g_type_register_static", | |
267 | "g_type_class_ref", | |
268 | "g_type_create_instance", | |
269 | "g_type_add_interface_static", | |
270 | "g_type_interface_add_prerequisite", | |
271 | "g_socket_connection_factory_lookup_type", | |
272 | /* libgpg */ | |
273 | "gpg_err_init", | |
7cfa84f5 MW |
274 | /* gnutls */ |
275 | "gnutls_global_init", | |
986d23bd MW |
276 | }; |
277 | ||
5113680f | 278 | |
fce3b5c3 MW |
279 | /** |
280 | * Hashtable hash function | |
281 | */ | |
282 | static u_int hash(backtrace_t *key) | |
283 | { | |
284 | enumerator_t *enumerator; | |
285 | void *addr; | |
286 | u_int hash = 0; | |
287 | ||
288 | enumerator = key->create_frame_enumerator(key); | |
289 | while (enumerator->enumerate(enumerator, &addr)) | |
290 | { | |
291 | hash = chunk_hash_inc(chunk_from_thing(addr), hash); | |
292 | } | |
293 | enumerator->destroy(enumerator); | |
294 | ||
295 | return hash; | |
296 | } | |
297 | ||
298 | /** | |
299 | * Hashtable equals function | |
300 | */ | |
301 | static bool equals(backtrace_t *a, backtrace_t *b) | |
302 | { | |
303 | return a->equals(a, b); | |
304 | } | |
305 | ||
eb4f4551 MW |
306 | /** |
307 | * Summarize and print backtraces | |
308 | */ | |
309 | static int print_traces(private_leak_detective_t *this, | |
310 | FILE *out, int thresh, bool detailed, int *whitelisted) | |
fce3b5c3 | 311 | { |
eb4f4551 | 312 | int leaks = 0; |
fce3b5c3 MW |
313 | memory_header_t *hdr; |
314 | enumerator_t *enumerator; | |
315 | hashtable_t *entries; | |
316 | struct { | |
317 | /** associated backtrace */ | |
318 | backtrace_t *backtrace; | |
319 | /** total size of all allocations */ | |
320 | size_t bytes; | |
321 | /** number of allocations */ | |
322 | u_int count; | |
323 | } *entry; | |
324 | ||
fce3b5c3 MW |
325 | uninstall_hooks(); |
326 | ||
327 | entries = hashtable_create((hashtable_hash_t)hash, | |
328 | (hashtable_equals_t)equals, 1024); | |
fce3b5c3 MW |
329 | for (hdr = first_header.next; hdr != NULL; hdr = hdr->next) |
330 | { | |
eb4f4551 MW |
331 | if (whitelisted && |
332 | hdr->backtrace->contains_function(hdr->backtrace, | |
333 | whitelist, countof(whitelist))) | |
334 | { | |
335 | (*whitelisted)++; | |
336 | continue; | |
337 | } | |
fce3b5c3 MW |
338 | entry = entries->get(entries, hdr->backtrace); |
339 | if (entry) | |
340 | { | |
341 | entry->bytes += hdr->bytes; | |
342 | entry->count++; | |
343 | } | |
344 | else | |
345 | { | |
346 | INIT(entry, | |
347 | .backtrace = hdr->backtrace, | |
348 | .bytes = hdr->bytes, | |
349 | .count = 1, | |
350 | ); | |
351 | entries->put(entries, hdr->backtrace, entry); | |
352 | } | |
eb4f4551 | 353 | leaks++; |
fce3b5c3 MW |
354 | } |
355 | enumerator = entries->create_enumerator(entries); | |
356 | while (enumerator->enumerate(enumerator, NULL, &entry)) | |
357 | { | |
eb4f4551 | 358 | if (!thresh || entry->bytes >= thresh) |
fce3b5c3 | 359 | { |
eb4f4551 | 360 | fprintf(out, "%d bytes total, %d allocations, %d bytes average:\n", |
fce3b5c3 | 361 | entry->bytes, entry->count, entry->bytes / entry->count); |
eb4f4551 | 362 | entry->backtrace->log(entry->backtrace, out, detailed); |
fce3b5c3 MW |
363 | } |
364 | free(entry); | |
365 | } | |
366 | enumerator->destroy(enumerator); | |
367 | entries->destroy(entries); | |
368 | ||
369 | install_hooks(); | |
eb4f4551 MW |
370 | return leaks; |
371 | } | |
372 | ||
373 | METHOD(leak_detective_t, report, void, | |
374 | private_leak_detective_t *this, bool detailed) | |
375 | { | |
376 | if (lib->leak_detective) | |
377 | { | |
378 | int leaks = 0, whitelisted = 0; | |
379 | ||
380 | leaks = print_traces(this, stderr, 0, detailed, &whitelisted); | |
381 | switch (leaks) | |
382 | { | |
383 | case 0: | |
384 | fprintf(stderr, "No leaks detected"); | |
385 | break; | |
386 | case 1: | |
387 | fprintf(stderr, "One leak detected"); | |
388 | break; | |
389 | default: | |
390 | fprintf(stderr, "%d leaks detected", leaks); | |
391 | break; | |
392 | } | |
393 | fprintf(stderr, ", %d suppressed by whitelist\n", whitelisted); | |
394 | } | |
395 | else | |
396 | { | |
397 | fprintf(stderr, "Leak detective disabled\n"); | |
398 | } | |
399 | } | |
400 | ||
b46776ae MW |
401 | METHOD(leak_detective_t, set_state, bool, |
402 | private_leak_detective_t *this, bool enable) | |
403 | { | |
404 | static struct sched_param oldparams; | |
405 | static int oldpolicy; | |
406 | struct sched_param params; | |
407 | pthread_t thread_id; | |
408 | ||
409 | if (enable == installed) | |
410 | { | |
411 | return installed; | |
412 | } | |
413 | thread_id = pthread_self(); | |
414 | if (enable) | |
415 | { | |
416 | install_hooks(); | |
417 | pthread_setschedparam(thread_id, oldpolicy, &oldparams); | |
418 | } | |
419 | else | |
420 | { | |
421 | pthread_getschedparam(thread_id, &oldpolicy, &oldparams); | |
422 | params.__sched_priority = sched_get_priority_max(SCHED_FIFO); | |
423 | pthread_setschedparam(thread_id, SCHED_FIFO, ¶ms); | |
424 | uninstall_hooks(); | |
425 | } | |
426 | installed = enable; | |
427 | return !installed; | |
428 | } | |
429 | ||
eb4f4551 MW |
430 | METHOD(leak_detective_t, usage, void, |
431 | private_leak_detective_t *this, FILE *out) | |
432 | { | |
433 | int oldpolicy, thresh; | |
434 | bool detailed; | |
435 | pthread_t thread_id = pthread_self(); | |
436 | struct sched_param oldparams, params; | |
437 | ||
438 | thresh = lib->settings->get_int(lib->settings, | |
439 | "libstrongswan.leak_detective.usage_threshold", 10240); | |
440 | detailed = lib->settings->get_bool(lib->settings, | |
441 | "libstrongswan.leak_detective.detailed", TRUE); | |
442 | ||
443 | pthread_getschedparam(thread_id, &oldpolicy, &oldparams); | |
444 | params.__sched_priority = sched_get_priority_max(SCHED_FIFO); | |
445 | pthread_setschedparam(thread_id, SCHED_FIFO, ¶ms); | |
446 | ||
447 | print_traces(this, out, thresh, detailed, NULL); | |
448 | ||
fce3b5c3 MW |
449 | pthread_setschedparam(thread_id, oldpolicy, &oldparams); |
450 | } | |
451 | ||
5113680f MW |
452 | /** |
453 | * Hook function for malloc() | |
454 | */ | |
6b3292da | 455 | void *malloc_hook(size_t bytes, const void *caller) |
5113680f MW |
456 | { |
457 | memory_header_t *hdr; | |
b7ef3f62 | 458 | memory_tail_t *tail; |
84b18d5f | 459 | pthread_t thread_id = pthread_self(); |
323f9f99 MW |
460 | int oldpolicy; |
461 | struct sched_param oldparams, params; | |
7daf5226 | 462 | |
323f9f99 | 463 | pthread_getschedparam(thread_id, &oldpolicy, &oldparams); |
7daf5226 | 464 | |
323f9f99 | 465 | params.__sched_priority = sched_get_priority_max(SCHED_FIFO); |
84b18d5f | 466 | pthread_setschedparam(thread_id, SCHED_FIFO, ¶ms); |
7daf5226 | 467 | |
73760ca5 | 468 | count_malloc++; |
5113680f | 469 | uninstall_hooks(); |
b7ef3f62 MW |
470 | hdr = malloc(sizeof(memory_header_t) + bytes + sizeof(memory_tail_t)); |
471 | tail = ((void*)hdr) + bytes + sizeof(memory_header_t); | |
986d23bd | 472 | /* set to something which causes crashes */ |
b7ef3f62 MW |
473 | memset(hdr, MEMORY_ALLOC_PATTERN, |
474 | sizeof(memory_header_t) + bytes + sizeof(memory_tail_t)); | |
7daf5226 | 475 | |
5113680f MW |
476 | hdr->magic = MEMORY_HEADER_MAGIC; |
477 | hdr->bytes = bytes; | |
549eba30 | 478 | hdr->backtrace = backtrace_create(2); |
b7ef3f62 | 479 | tail->magic = MEMORY_TAIL_MAGIC; |
269f7f44 | 480 | install_hooks(); |
7daf5226 | 481 | |
5113680f MW |
482 | /* insert at the beginning of the list */ |
483 | hdr->next = first_header.next; | |
484 | if (hdr->next) | |
485 | { | |
486 | hdr->next->previous = hdr; | |
487 | } | |
488 | hdr->previous = &first_header; | |
489 | first_header.next = hdr; | |
7daf5226 | 490 | |
84b18d5f | 491 | pthread_setschedparam(thread_id, oldpolicy, &oldparams); |
7daf5226 | 492 | |
5113680f MW |
493 | return hdr + 1; |
494 | } | |
495 | ||
496 | /** | |
497 | * Hook function for free() | |
498 | */ | |
6b3292da | 499 | void free_hook(void *ptr, const void *caller) |
5113680f | 500 | { |
587ebae7 | 501 | memory_header_t *hdr, *current; |
b7ef3f62 | 502 | memory_tail_t *tail; |
323f9f99 | 503 | backtrace_t *backtrace; |
84b18d5f | 504 | pthread_t thread_id = pthread_self(); |
323f9f99 MW |
505 | int oldpolicy; |
506 | struct sched_param oldparams, params; | |
587ebae7 | 507 | bool found = FALSE; |
7daf5226 | 508 | |
5113680f MW |
509 | /* allow freeing of NULL */ |
510 | if (ptr == NULL) | |
511 | { | |
512 | return; | |
513 | } | |
b7ef3f62 MW |
514 | hdr = ptr - sizeof(memory_header_t); |
515 | tail = ptr + hdr->bytes; | |
7daf5226 | 516 | |
84b18d5f | 517 | pthread_getschedparam(thread_id, &oldpolicy, &oldparams); |
7daf5226 | 518 | |
323f9f99 | 519 | params.__sched_priority = sched_get_priority_max(SCHED_FIFO); |
84b18d5f | 520 | pthread_setschedparam(thread_id, SCHED_FIFO, ¶ms); |
7daf5226 | 521 | |
73760ca5 | 522 | count_free++; |
269f7f44 | 523 | uninstall_hooks(); |
6c45e622 MW |
524 | if (hdr->magic != MEMORY_HEADER_MAGIC || |
525 | tail->magic != MEMORY_TAIL_MAGIC) | |
5113680f | 526 | { |
587ebae7 MW |
527 | for (current = &first_header; current != NULL; current = current->next) |
528 | { | |
529 | if (current == hdr) | |
530 | { | |
531 | found = TRUE; | |
532 | break; | |
533 | } | |
534 | } | |
535 | if (found) | |
536 | { | |
537 | /* memory was allocated by our hooks but is corrupted */ | |
538 | fprintf(stderr, "freeing corrupted memory (%p): " | |
539 | "header magic 0x%x, tail magic 0x%x:\n", | |
540 | ptr, hdr->magic, tail->magic); | |
541 | } | |
542 | else | |
543 | { | |
544 | /* memory was not allocated by our hooks */ | |
545 | fprintf(stderr, "freeing invalid memory (%p)", ptr); | |
546 | } | |
549eba30 | 547 | backtrace = backtrace_create(2); |
091d1780 | 548 | backtrace->log(backtrace, stderr, TRUE); |
f7237cf3 | 549 | backtrace->destroy(backtrace); |
5113680f | 550 | } |
6c45e622 | 551 | else |
b7ef3f62 | 552 | { |
6c45e622 MW |
553 | /* remove item from list */ |
554 | if (hdr->next) | |
555 | { | |
556 | hdr->next->previous = hdr->previous; | |
557 | } | |
558 | hdr->previous->next = hdr->next; | |
f7237cf3 | 559 | hdr->backtrace->destroy(hdr->backtrace); |
7daf5226 | 560 | |
6c45e622 | 561 | /* clear MAGIC, set mem to something remarkable */ |
587ebae7 MW |
562 | memset(hdr, MEMORY_FREE_PATTERN, |
563 | sizeof(memory_header_t) + hdr->bytes + sizeof(memory_tail_t)); | |
7daf5226 | 564 | |
6c45e622 MW |
565 | free(hdr); |
566 | } | |
7daf5226 | 567 | |
5113680f | 568 | install_hooks(); |
6c90949f | 569 | pthread_setschedparam(thread_id, oldpolicy, &oldparams); |
5113680f MW |
570 | } |
571 | ||
572 | /** | |
573 | * Hook function for realloc() | |
574 | */ | |
6b3292da | 575 | void *realloc_hook(void *old, size_t bytes, const void *caller) |
5113680f | 576 | { |
a401efd0 | 577 | memory_header_t *hdr; |
b7ef3f62 | 578 | memory_tail_t *tail; |
f7237cf3 | 579 | backtrace_t *backtrace; |
84b18d5f | 580 | pthread_t thread_id = pthread_self(); |
323f9f99 MW |
581 | int oldpolicy; |
582 | struct sched_param oldparams, params; | |
7daf5226 | 583 | |
5113680f MW |
584 | /* allow reallocation of NULL */ |
585 | if (old == NULL) | |
586 | { | |
587 | return malloc_hook(bytes, caller); | |
588 | } | |
7daf5226 | 589 | |
a401efd0 | 590 | hdr = old - sizeof(memory_header_t); |
b7ef3f62 | 591 | tail = old + hdr->bytes; |
7daf5226 | 592 | |
84b18d5f | 593 | pthread_getschedparam(thread_id, &oldpolicy, &oldparams); |
7daf5226 | 594 | |
84b18d5f TB |
595 | params.__sched_priority = sched_get_priority_max(SCHED_FIFO); |
596 | pthread_setschedparam(thread_id, SCHED_FIFO, ¶ms); | |
7daf5226 | 597 | |
73760ca5 | 598 | count_realloc++; |
a401efd0 | 599 | uninstall_hooks(); |
6c45e622 MW |
600 | if (hdr->magic != MEMORY_HEADER_MAGIC || |
601 | tail->magic != MEMORY_TAIL_MAGIC) | |
b7ef3f62 | 602 | { |
6499354e MW |
603 | fprintf(stderr, "reallocating invalid memory (%p):\n" |
604 | "header magic 0x%x:\n", old, hdr->magic); | |
549eba30 | 605 | backtrace = backtrace_create(2); |
091d1780 | 606 | backtrace->log(backtrace, stderr, TRUE); |
f7237cf3 | 607 | backtrace->destroy(backtrace); |
b7ef3f62 | 608 | } |
6499354e MW |
609 | else |
610 | { | |
611 | /* clear tail magic, allocate, set tail magic */ | |
612 | memset(&tail->magic, MEMORY_ALLOC_PATTERN, sizeof(tail->magic)); | |
613 | } | |
b7ef3f62 MW |
614 | hdr = realloc(hdr, sizeof(memory_header_t) + bytes + sizeof(memory_tail_t)); |
615 | tail = ((void*)hdr) + bytes + sizeof(memory_header_t); | |
616 | tail->magic = MEMORY_TAIL_MAGIC; | |
6c45e622 | 617 | |
a401efd0 MW |
618 | /* update statistics */ |
619 | hdr->bytes = bytes; | |
f7237cf3 | 620 | hdr->backtrace->destroy(hdr->backtrace); |
549eba30 | 621 | hdr->backtrace = backtrace_create(2); |
6c45e622 | 622 | |
a401efd0 MW |
623 | /* update header of linked list neighbours */ |
624 | if (hdr->next) | |
625 | { | |
626 | hdr->next->previous = hdr; | |
627 | } | |
628 | hdr->previous->next = hdr; | |
629 | install_hooks(); | |
84b18d5f | 630 | pthread_setschedparam(thread_id, oldpolicy, &oldparams); |
a401efd0 | 631 | return hdr + 1; |
5113680f MW |
632 | } |
633 | ||
42e0f26e MW |
634 | METHOD(leak_detective_t, destroy, void, |
635 | private_leak_detective_t *this) | |
5113680f | 636 | { |
552cc11b | 637 | if (installed) |
9cc7a297 MW |
638 | { |
639 | uninstall_hooks(); | |
9cc7a297 | 640 | } |
552cc11b | 641 | free(this); |
6b3292da MW |
642 | } |
643 | ||
552cc11b MW |
644 | /* |
645 | * see header file | |
73760ca5 | 646 | */ |
552cc11b | 647 | leak_detective_t *leak_detective_create() |
73760ca5 | 648 | { |
42e0f26e MW |
649 | private_leak_detective_t *this; |
650 | ||
651 | INIT(this, | |
652 | .public = { | |
653 | .report = _report, | |
fce3b5c3 | 654 | .usage = _usage, |
b46776ae | 655 | .set_state = _set_state, |
42e0f26e MW |
656 | .destroy = _destroy, |
657 | }, | |
658 | ); | |
7daf5226 | 659 | |
552cc11b | 660 | if (getenv("LEAK_DETECTIVE_DISABLE") == NULL) |
73760ca5 | 661 | { |
7a485e90 | 662 | cpu_set_t mask; |
7daf5226 | 663 | |
7a485e90 MW |
664 | CPU_ZERO(&mask); |
665 | CPU_SET(0, &mask); | |
7daf5226 | 666 | |
7a485e90 MW |
667 | if (sched_setaffinity(0, sizeof(cpu_set_t), &mask) != 0) |
668 | { | |
669 | fprintf(stderr, "setting CPU affinity failed: %m"); | |
670 | } | |
7daf5226 | 671 | |
552cc11b | 672 | install_hooks(); |
73760ca5 | 673 | } |
552cc11b | 674 | return &this->public; |
73760ca5 MW |
675 | } |
676 |