leak-detective: Register OS X specific hooks just once
[strongswan.git] / src / libstrongswan / utils / leak_detective.c
1 /*
2 * Copyright (C) 2013 Tobias Brunner
3 * Copyright (C) 2006-2013 Martin Willi
4 * Hochschule fuer Technik Rapperswil
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 */
16
17 #define _GNU_SOURCE
18 #include <stddef.h>
19 #include <string.h>
20 #include <stdio.h>
21 #include <signal.h>
22 #include <sys/socket.h>
23 #include <netinet/in.h>
24 #include <arpa/inet.h>
25 #include <unistd.h>
26 #include <syslog.h>
27 #include <netdb.h>
28 #include <locale.h>
29 #include <dlfcn.h>
30 #include <time.h>
31 #include <errno.h>
32
33 #ifdef __APPLE__
34 #include <sys/mman.h>
35 #include <malloc/malloc.h>
36 /* overload some of our types clashing with mach */
37 #define host_t strongswan_host_t
38 #define processor_t strongswan_processor_t
39 #define thread_t strongswan_thread_t
40 #endif /* __APPLE__ */
41
42 #include "leak_detective.h"
43
44 #include <library.h>
45 #include <utils/debug.h>
46 #include <utils/backtrace.h>
47 #include <collections/hashtable.h>
48 #include <threading/thread_value.h>
49 #include <threading/spinlock.h>
50
51 typedef struct private_leak_detective_t private_leak_detective_t;
52
53 /**
54 * private data of leak_detective
55 */
56 struct private_leak_detective_t {
57
58 /**
59 * public functions
60 */
61 leak_detective_t public;
62
63 /**
64 * Registered report() function
65 */
66 leak_detective_report_cb_t report_cb;
67
68 /**
69 * Registered report() summary function
70 */
71 leak_detective_summary_cb_t report_scb;
72
73 /**
74 * Registered user data for callbacks
75 */
76 void *report_data;
77 };
78
79 /**
80 * Magic value which helps to detect memory corruption. Yummy!
81 */
82 #define MEMORY_HEADER_MAGIC 0x7ac0be11
83
84 /**
85 * Magic written to tail of allocation
86 */
87 #define MEMORY_TAIL_MAGIC 0xcafebabe
88
89 /**
90 * Pattern which is filled in memory before freeing it
91 */
92 #define MEMORY_FREE_PATTERN 0xFF
93
94 /**
95 * Pattern which is filled in newly allocated memory
96 */
97 #define MEMORY_ALLOC_PATTERN 0xEE
98
99 typedef struct memory_header_t memory_header_t;
100 typedef struct memory_tail_t memory_tail_t;
101
102 /**
103 * Header which is prepended to each allocated memory block
104 */
105 struct memory_header_t {
106
107 /**
108 * Pointer to previous entry in linked list
109 */
110 memory_header_t *previous;
111
112 /**
113 * Pointer to next entry in linked list
114 */
115 memory_header_t *next;
116
117 /**
118 * backtrace taken during (re-)allocation
119 */
120 backtrace_t *backtrace;
121
122 /**
123 * Padding to make sizeof(memory_header_t) == 32
124 */
125 u_int32_t padding[sizeof(void*) == sizeof(u_int32_t) ? 3 : 0];
126
127 /**
128 * Number of bytes following after the header
129 */
130 u_int32_t bytes;
131
132 /**
133 * magic bytes to detect bad free or heap underflow, MEMORY_HEADER_MAGIC
134 */
135 u_int32_t magic;
136
137 }__attribute__((__packed__));
138
139 /**
140 * tail appended to each allocated memory block
141 */
142 struct memory_tail_t {
143
144 /**
145 * Magic bytes to detect heap overflow, MEMORY_TAIL_MAGIC
146 */
147 u_int32_t magic;
148
149 }__attribute__((__packed__));
150
151 /**
152 * first mem header is just a dummy to chain
153 * the others on it...
154 */
155 static memory_header_t first_header = {
156 .magic = MEMORY_HEADER_MAGIC,
157 };
158
159 /**
160 * Spinlock to access header linked list
161 */
162 static spinlock_t *lock;
163
164 /**
165 * Is leak detection currently enabled?
166 */
167 static bool enabled = FALSE;
168
169 /**
170 * Is leak detection disabled for the current thread?
171 */
172 static thread_value_t *thread_disabled;
173
174 /**
175 * Installs the malloc hooks, enables leak detection
176 */
177 static void enable_leak_detective()
178 {
179 enabled = TRUE;
180 }
181
182 /**
183 * Uninstalls the malloc hooks, disables leak detection
184 */
185 static void disable_leak_detective()
186 {
187 enabled = FALSE;
188 }
189
190 /**
191 * Enable/Disable leak detective for the current thread
192 *
193 * @return Previous value
194 */
195 static bool enable_thread(bool enable)
196 {
197 bool before;
198
199 before = thread_disabled->get(thread_disabled) == NULL;
200 thread_disabled->set(thread_disabled, enable ? NULL : (void*)TRUE);
201 return before;
202 }
203
204 /**
205 * Add a header to the beginning of the list
206 */
207 static void add_hdr(memory_header_t *hdr)
208 {
209 lock->lock(lock);
210 hdr->next = first_header.next;
211 if (hdr->next)
212 {
213 hdr->next->previous = hdr;
214 }
215 hdr->previous = &first_header;
216 first_header.next = hdr;
217 lock->unlock(lock);
218 }
219
220 /**
221 * Remove a header from the list
222 */
223 static void remove_hdr(memory_header_t *hdr)
224 {
225 lock->lock(lock);
226 if (hdr->next)
227 {
228 hdr->next->previous = hdr->previous;
229 }
230 hdr->previous->next = hdr->next;
231 lock->unlock(lock);
232 }
233
234 /**
235 * Check if a header is in the list
236 */
237 static bool has_hdr(memory_header_t *hdr)
238 {
239 memory_header_t *current;
240 bool found = FALSE;
241
242 lock->lock(lock);
243 for (current = &first_header; current != NULL; current = current->next)
244 {
245 if (current == hdr)
246 {
247 found = TRUE;
248 break;
249 }
250 }
251 lock->unlock(lock);
252
253 return found;
254 }
255
256 #ifdef __APPLE__
257
258 /**
259 * Copy of original default zone, with functions we call in hooks
260 */
261 static malloc_zone_t original;
262
263 /**
264 * Call original malloc()
265 */
266 static void* real_malloc(size_t size)
267 {
268 return original.malloc(malloc_default_zone(), size);
269 }
270
271 /**
272 * Call original free()
273 */
274 static void real_free(void *ptr)
275 {
276 original.free(malloc_default_zone(), ptr);
277 }
278
279 /**
280 * Call original realloc()
281 */
282 static void* real_realloc(void *ptr, size_t size)
283 {
284 return original.realloc(malloc_default_zone(), ptr, size);
285 }
286
287 /**
288 * Hook definition: static function with _hook suffix, takes additional zone
289 */
290 #define HOOK(ret, name, ...) \
291 static ret name ## _hook(malloc_zone_t *_z, __VA_ARGS__)
292
293 /**
294 * forward declaration of hooks
295 */
296 HOOK(void*, malloc, size_t bytes);
297 HOOK(void*, calloc, size_t nmemb, size_t size);
298 HOOK(void*, valloc, size_t size);
299 HOOK(void, free, void *ptr);
300 HOOK(void*, realloc, void *old, size_t bytes);
301
302 /**
303 * malloc zone size(), must consider the memory header prepended
304 */
305 HOOK(size_t, size, const void *ptr)
306 {
307 bool before;
308 size_t size;
309
310 if (enabled)
311 {
312 before = enable_thread(FALSE);
313 if (before)
314 {
315 ptr -= sizeof(memory_header_t);
316 }
317 }
318 size = original.size(malloc_default_zone(), ptr);
319 if (enabled)
320 {
321 enable_thread(before);
322 }
323 return size;
324 }
325
326 /**
327 * Version of malloc zones we currently support
328 */
329 #define MALLOC_ZONE_VERSION 8 /* Snow Leopard */
330
331 /**
332 * Hook-in our malloc functions into the default zone
333 */
334 static bool register_hooks()
335 {
336 static bool once = FALSE;
337 malloc_zone_t *zone;
338 void *page;
339
340 if (once)
341 {
342 return TRUE;
343 }
344 once = TRUE;
345
346 zone = malloc_default_zone();
347 if (zone->version != MALLOC_ZONE_VERSION)
348 {
349 DBG1(DBG_CFG, "malloc zone version %d unsupported (requiring %d)",
350 zone->version, MALLOC_ZONE_VERSION);
351 return FALSE;
352 }
353
354 original = *zone;
355
356 page = (void*)((uintptr_t)zone / getpagesize() * getpagesize());
357 if (mprotect(page, getpagesize(), PROT_WRITE | PROT_READ) != 0)
358 {
359 DBG1(DBG_CFG, "malloc zone unprotection failed: %s", strerror(errno));
360 return FALSE;
361 }
362
363 zone->size = size_hook;
364 zone->malloc = malloc_hook;
365 zone->calloc = calloc_hook;
366 zone->valloc = valloc_hook;
367 zone->free = free_hook;
368 zone->realloc = realloc_hook;
369
370 /* those other functions can be NULLed out to not use them */
371 zone->batch_malloc = NULL;
372 zone->batch_free = NULL;
373 zone->memalign = NULL;
374 zone->free_definite_size = NULL;
375
376 return TRUE;
377 }
378
379 #else /* !__APPLE__ */
380
381 /**
382 * dlsym() might do a malloc(), but we can't do one before we get the malloc()
383 * function pointer. Use this minimalistic malloc implementation instead.
384 */
385 static void* malloc_for_dlsym(size_t size)
386 {
387 static char buf[1024] = {};
388 static size_t used = 0;
389 char *ptr;
390
391 /* roundup to a multiple of 32 */
392 size = (size - 1) / 32 * 32 + 32;
393
394 if (used + size > sizeof(buf))
395 {
396 return NULL;
397 }
398 ptr = buf + used;
399 used += size;
400 return ptr;
401 }
402
403 /**
404 * Lookup a malloc function, while disabling wrappers
405 */
406 static void* get_malloc_fn(char *name)
407 {
408 bool before = FALSE;
409 void *fn;
410
411 if (enabled)
412 {
413 before = enable_thread(FALSE);
414 }
415 fn = dlsym(RTLD_NEXT, name);
416 if (enabled)
417 {
418 enable_thread(before);
419 }
420 return fn;
421 }
422
423 /**
424 * Call original malloc()
425 */
426 static void* real_malloc(size_t size)
427 {
428 static void* (*fn)(size_t size);
429 static int recursive = 0;
430
431 if (!fn)
432 {
433 /* checking recursiveness should actually be thread-specific. But as
434 * it is very likely that the first allocation is done before we go
435 * multi-threaded, we keep it simple. */
436 if (recursive)
437 {
438 return malloc_for_dlsym(size);
439 }
440 recursive++;
441 fn = get_malloc_fn("malloc");
442 recursive--;
443 }
444 return fn(size);
445 }
446
447 /**
448 * Call original free()
449 */
450 static void real_free(void *ptr)
451 {
452 static void (*fn)(void *ptr);
453
454 if (!fn)
455 {
456 fn = get_malloc_fn("free");
457 }
458 return fn(ptr);
459 }
460
461 /**
462 * Call original realloc()
463 */
464 static void* real_realloc(void *ptr, size_t size)
465 {
466 static void* (*fn)(void *ptr, size_t size);
467
468 if (!fn)
469 {
470 fn = get_malloc_fn("realloc");
471 }
472 return fn(ptr, size);
473 }
474
475 /**
476 * Hook definition: plain function overloading existing malloc calls
477 */
478 #define HOOK(ret, name, ...) ret name(__VA_ARGS__)
479
480 /**
481 * Hook initialization when not using hooks, resolve functions.
482 */
483 static bool register_hooks()
484 {
485 void *buf = real_malloc(8);
486 real_realloc(buf, 16);
487 real_free(buf);
488 return TRUE;
489 }
490
491 #endif /* !__APPLE__ */
492
493 /**
494 * Leak report white list
495 *
496 * List of functions using static allocation buffers or should be suppressed
497 * otherwise on leak report.
498 */
499 char *whitelist[] = {
500 /* backtraces, including own */
501 "backtrace_create",
502 "safe_strerror",
503 /* pthread stuff */
504 "pthread_create",
505 "pthread_setspecific",
506 "__pthread_setspecific",
507 /* glibc functions */
508 "inet_ntoa",
509 "strerror",
510 "getprotobyname",
511 "getprotobynumber",
512 "getservbyport",
513 "getservbyname",
514 "gethostbyname",
515 "gethostbyname2",
516 "gethostbyname_r",
517 "gethostbyname2_r",
518 "getnetbyname",
519 "getpwnam_r",
520 "getgrnam_r",
521 "register_printf_function",
522 "register_printf_specifier",
523 "syslog",
524 "vsyslog",
525 "__syslog_chk",
526 "__vsyslog_chk",
527 "getaddrinfo",
528 "setlocale",
529 "getpass",
530 "getpwent_r",
531 "setpwent",
532 "endpwent",
533 "getspnam_r",
534 "getpwuid_r",
535 "initgroups",
536 "tzset",
537 /* ignore dlopen, as we do not dlclose to get proper leak reports */
538 "dlopen",
539 "dlerror",
540 "dlclose",
541 "dlsym",
542 /* mysql functions */
543 "mysql_init_character_set",
544 "init_client_errs",
545 "my_thread_init",
546 /* fastcgi library */
547 "FCGX_Init",
548 /* libxml */
549 "xmlInitCharEncodingHandlers",
550 "xmlInitParser",
551 "xmlInitParserCtxt",
552 /* libcurl */
553 "Curl_client_write",
554 /* ClearSilver */
555 "nerr_init",
556 /* libgcrypt */
557 "gcry_control",
558 "gcry_check_version",
559 "gcry_randomize",
560 "gcry_create_nonce",
561 /* OpenSSL: These are needed for unit-tests only, the openssl plugin
562 * does properly clean up any memory during destroy(). */
563 "ECDSA_do_sign_ex",
564 "ECDSA_verify",
565 "RSA_new_method",
566 /* NSPR */
567 "PR_CallOnce",
568 /* libapr */
569 "apr_pool_create_ex",
570 /* glib */
571 "g_type_init_with_debug_flags",
572 "g_type_register_static",
573 "g_type_class_ref",
574 "g_type_create_instance",
575 "g_type_add_interface_static",
576 "g_type_interface_add_prerequisite",
577 "g_socket_connection_factory_lookup_type",
578 /* libgpg */
579 "gpg_err_init",
580 /* gnutls */
581 "gnutls_global_init",
582 };
583
584 /**
585 * Some functions are hard to whitelist, as they don't use a symbol directly.
586 * Use some static initialization to suppress them on leak reports
587 */
588 static void init_static_allocations()
589 {
590 tzset();
591 }
592
593 /**
594 * Hashtable hash function
595 */
596 static u_int hash(backtrace_t *key)
597 {
598 enumerator_t *enumerator;
599 void *addr;
600 u_int hash = 0;
601
602 enumerator = key->create_frame_enumerator(key);
603 while (enumerator->enumerate(enumerator, &addr))
604 {
605 hash = chunk_hash_inc(chunk_from_thing(addr), hash);
606 }
607 enumerator->destroy(enumerator);
608
609 return hash;
610 }
611
612 /**
613 * Hashtable equals function
614 */
615 static bool equals(backtrace_t *a, backtrace_t *b)
616 {
617 return a->equals(a, b);
618 }
619
620 /**
621 * Summarize and print backtraces
622 */
623 static int print_traces(private_leak_detective_t *this,
624 leak_detective_report_cb_t cb, void *user,
625 int thresh, int thresh_count,
626 bool detailed, int *whitelisted, size_t *sum)
627 {
628 int leaks = 0;
629 memory_header_t *hdr;
630 enumerator_t *enumerator;
631 hashtable_t *entries;
632 struct {
633 /** associated backtrace */
634 backtrace_t *backtrace;
635 /** total size of all allocations */
636 size_t bytes;
637 /** number of allocations */
638 u_int count;
639 } *entry;
640 bool before;
641
642 before = enable_thread(FALSE);
643
644 entries = hashtable_create((hashtable_hash_t)hash,
645 (hashtable_equals_t)equals, 1024);
646 lock->lock(lock);
647 for (hdr = first_header.next; hdr != NULL; hdr = hdr->next)
648 {
649 if (whitelisted &&
650 hdr->backtrace->contains_function(hdr->backtrace,
651 whitelist, countof(whitelist)))
652 {
653 (*whitelisted)++;
654 continue;
655 }
656 entry = entries->get(entries, hdr->backtrace);
657 if (entry)
658 {
659 entry->bytes += hdr->bytes;
660 entry->count++;
661 }
662 else
663 {
664 INIT(entry,
665 .backtrace = hdr->backtrace->clone(hdr->backtrace),
666 .bytes = hdr->bytes,
667 .count = 1,
668 );
669 entries->put(entries, entry->backtrace, entry);
670 }
671 if (sum)
672 {
673 *sum += hdr->bytes;
674 }
675 leaks++;
676 }
677 lock->unlock(lock);
678
679 enumerator = entries->create_enumerator(entries);
680 while (enumerator->enumerate(enumerator, NULL, &entry))
681 {
682 if (cb)
683 {
684 if (!thresh || entry->bytes >= thresh)
685 {
686 if (!thresh_count || entry->count >= thresh_count)
687 {
688 this->report_cb(this->report_data, entry->count,
689 entry->bytes, entry->backtrace, detailed);
690 }
691 }
692 }
693 entry->backtrace->destroy(entry->backtrace);
694 free(entry);
695 }
696 enumerator->destroy(enumerator);
697 entries->destroy(entries);
698
699 enable_thread(before);
700 return leaks;
701 }
702
703 METHOD(leak_detective_t, report, void,
704 private_leak_detective_t *this, bool detailed)
705 {
706 if (lib->leak_detective)
707 {
708 int leaks, whitelisted = 0;
709 size_t sum = 0;
710
711 leaks = print_traces(this, this->report_cb, this->report_data,
712 0, 0, detailed, &whitelisted, &sum);
713 if (this->report_scb)
714 {
715 this->report_scb(this->report_data, leaks, sum, whitelisted);
716 }
717 }
718 }
719
720 METHOD(leak_detective_t, set_report_cb, void,
721 private_leak_detective_t *this, leak_detective_report_cb_t cb,
722 leak_detective_summary_cb_t scb, void *user)
723 {
724 this->report_cb = cb;
725 this->report_scb = scb;
726 this->report_data = user;
727 }
728
729 METHOD(leak_detective_t, leaks, int,
730 private_leak_detective_t *this)
731 {
732 int whitelisted = 0;
733
734 return print_traces(this, NULL, NULL, 0, 0, FALSE, &whitelisted, NULL);
735 }
736
737 METHOD(leak_detective_t, set_state, bool,
738 private_leak_detective_t *this, bool enable)
739 {
740 return enable_thread(enable);
741 }
742
743 METHOD(leak_detective_t, usage, void,
744 private_leak_detective_t *this, leak_detective_report_cb_t cb,
745 leak_detective_summary_cb_t scb, void *user)
746 {
747 bool detailed;
748 int thresh, thresh_count, leaks, whitelisted = 0;
749 size_t sum = 0;
750
751 thresh = lib->settings->get_int(lib->settings,
752 "libstrongswan.leak_detective.usage_threshold", 10240);
753 thresh_count = lib->settings->get_int(lib->settings,
754 "libstrongswan.leak_detective.usage_threshold_count", 0);
755 detailed = lib->settings->get_bool(lib->settings,
756 "libstrongswan.leak_detective.detailed", TRUE);
757
758 leaks = print_traces(this, cb, user, thresh, thresh_count,
759 detailed, &whitelisted, &sum);
760 if (scb)
761 {
762 scb(user, leaks, sum, whitelisted);
763 }
764 }
765
766 /**
767 * Wrapped malloc() function
768 */
769 HOOK(void*, malloc, size_t bytes)
770 {
771 memory_header_t *hdr;
772 memory_tail_t *tail;
773 bool before;
774
775 if (!enabled || thread_disabled->get(thread_disabled))
776 {
777 return real_malloc(bytes);
778 }
779
780 hdr = real_malloc(sizeof(memory_header_t) + bytes + sizeof(memory_tail_t));
781 tail = ((void*)hdr) + bytes + sizeof(memory_header_t);
782 /* set to something which causes crashes */
783 memset(hdr, MEMORY_ALLOC_PATTERN,
784 sizeof(memory_header_t) + bytes + sizeof(memory_tail_t));
785
786 before = enable_thread(FALSE);
787 hdr->backtrace = backtrace_create(2);
788 enable_thread(before);
789
790 hdr->magic = MEMORY_HEADER_MAGIC;
791 hdr->bytes = bytes;
792 tail->magic = MEMORY_TAIL_MAGIC;
793
794 add_hdr(hdr);
795
796 return hdr + 1;
797 }
798
799 /**
800 * Wrapped calloc() function
801 */
802 HOOK(void*, calloc, size_t nmemb, size_t size)
803 {
804 void *ptr;
805
806 size *= nmemb;
807 ptr = malloc(size);
808 memset(ptr, 0, size);
809
810 return ptr;
811 }
812
813 /**
814 * Wrapped valloc(), TODO: currently not supported
815 */
816 HOOK(void*, valloc, size_t size)
817 {
818 DBG1(DBG_LIB, "valloc() used, but leak-detective hook missing");
819 return NULL;
820 }
821
822 /**
823 * Wrapped free() function
824 */
825 HOOK(void, free, void *ptr)
826 {
827 memory_header_t *hdr;
828 memory_tail_t *tail;
829 backtrace_t *backtrace;
830 bool before;
831
832 if (!enabled || thread_disabled->get(thread_disabled))
833 {
834 real_free(ptr);
835 return;
836 }
837 /* allow freeing of NULL */
838 if (ptr == NULL)
839 {
840 return;
841 }
842 hdr = ptr - sizeof(memory_header_t);
843 tail = ptr + hdr->bytes;
844
845 before = enable_thread(FALSE);
846 if (hdr->magic != MEMORY_HEADER_MAGIC ||
847 tail->magic != MEMORY_TAIL_MAGIC)
848 {
849 if (has_hdr(hdr))
850 {
851 /* memory was allocated by our hooks but is corrupted */
852 fprintf(stderr, "freeing corrupted memory (%p): "
853 "header magic 0x%x, tail magic 0x%x:\n",
854 ptr, hdr->magic, tail->magic);
855 }
856 else
857 {
858 /* memory was not allocated by our hooks */
859 fprintf(stderr, "freeing invalid memory (%p)\n", ptr);
860 }
861 backtrace = backtrace_create(2);
862 backtrace->log(backtrace, stderr, TRUE);
863 backtrace->destroy(backtrace);
864 }
865 else
866 {
867 remove_hdr(hdr);
868
869 hdr->backtrace->destroy(hdr->backtrace);
870
871 /* clear MAGIC, set mem to something remarkable */
872 memset(hdr, MEMORY_FREE_PATTERN,
873 sizeof(memory_header_t) + hdr->bytes + sizeof(memory_tail_t));
874
875 real_free(hdr);
876 }
877 enable_thread(before);
878 }
879
880 /**
881 * Wrapped realloc() function
882 */
883 HOOK(void*, realloc, void *old, size_t bytes)
884 {
885 memory_header_t *hdr;
886 memory_tail_t *tail;
887 backtrace_t *backtrace;
888 bool before;
889
890 if (!enabled || thread_disabled->get(thread_disabled))
891 {
892 return real_realloc(old, bytes);
893 }
894 /* allow reallocation of NULL */
895 if (old == NULL)
896 {
897 return malloc(bytes);
898 }
899 /* handle zero size as a free() */
900 if (bytes == 0)
901 {
902 free(old);
903 return NULL;
904 }
905
906 hdr = old - sizeof(memory_header_t);
907 tail = old + hdr->bytes;
908
909 remove_hdr(hdr);
910
911 if (hdr->magic != MEMORY_HEADER_MAGIC ||
912 tail->magic != MEMORY_TAIL_MAGIC)
913 {
914 fprintf(stderr, "reallocating invalid memory (%p):\n"
915 "header magic 0x%x:\n", old, hdr->magic);
916 backtrace = backtrace_create(2);
917 backtrace->log(backtrace, stderr, TRUE);
918 backtrace->destroy(backtrace);
919 }
920 else
921 {
922 /* clear tail magic, allocate, set tail magic */
923 memset(&tail->magic, MEMORY_ALLOC_PATTERN, sizeof(tail->magic));
924 }
925 hdr = real_realloc(hdr,
926 sizeof(memory_header_t) + bytes + sizeof(memory_tail_t));
927 tail = ((void*)hdr) + bytes + sizeof(memory_header_t);
928 tail->magic = MEMORY_TAIL_MAGIC;
929
930 /* update statistics */
931 hdr->bytes = bytes;
932
933 before = enable_thread(FALSE);
934 hdr->backtrace->destroy(hdr->backtrace);
935 hdr->backtrace = backtrace_create(2);
936 enable_thread(before);
937
938 add_hdr(hdr);
939
940 return hdr + 1;
941 }
942
943 METHOD(leak_detective_t, destroy, void,
944 private_leak_detective_t *this)
945 {
946 disable_leak_detective();
947 lock->destroy(lock);
948 thread_disabled->destroy(thread_disabled);
949 free(this);
950 first_header.next = NULL;
951 }
952
953 /*
954 * see header file
955 */
956 leak_detective_t *leak_detective_create()
957 {
958 private_leak_detective_t *this;
959
960 INIT(this,
961 .public = {
962 .report = _report,
963 .set_report_cb = _set_report_cb,
964 .usage = _usage,
965 .leaks = _leaks,
966 .set_state = _set_state,
967 .destroy = _destroy,
968 },
969 );
970
971 lock = spinlock_create();
972 thread_disabled = thread_value_create(NULL);
973
974 init_static_allocations();
975
976 if (getenv("LEAK_DETECTIVE_DISABLE") == NULL)
977 {
978 if (register_hooks())
979 {
980 enable_leak_detective();
981 }
982 }
983 return &this->public;
984 }