2 * Copyright (C) 2013-2018 Tobias Brunner
3 * Copyright (C) 2006-2013 Martin Willi
4 * HSR Hochschule fuer Technik Rapperswil
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>.
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
32 #include <malloc/malloc.h>
33 /* overload some of our types clashing with mach */
34 #define host_t strongswan_host_t
35 #define processor_t strongswan_processor_t
36 #define thread_t strongswan_thread_t
37 #endif /* __APPLE__ */
39 #include "leak_detective.h"
42 #include <utils/utils.h>
43 #include <utils/debug.h>
44 #include <utils/backtrace.h>
45 #include <collections/hashtable.h>
46 #include <threading/thread_value.h>
47 #include <threading/spinlock.h>
49 typedef struct private_leak_detective_t private_leak_detective_t
;
52 * private data of leak_detective
54 struct private_leak_detective_t
{
59 leak_detective_t
public;
62 * Registered report() function
64 leak_detective_report_cb_t report_cb
;
67 * Registered report() summary function
69 leak_detective_summary_cb_t report_scb
;
72 * Registered user data for callbacks
78 * Magic value which helps to detect memory corruption. Yummy!
80 #define MEMORY_HEADER_MAGIC 0x7ac0be11
83 * Magic written to tail of allocation
85 #define MEMORY_TAIL_MAGIC 0xcafebabe
88 * Pattern which is filled in memory before freeing it
90 #define MEMORY_FREE_PATTERN 0xFF
93 * Pattern which is filled in newly allocated memory
95 #define MEMORY_ALLOC_PATTERN 0xEE
97 typedef struct memory_header_t memory_header_t
;
98 typedef struct memory_tail_t memory_tail_t
;
101 * Header which is prepended to each allocated memory block
103 struct memory_header_t
{
106 * Pointer to previous entry in linked list
108 memory_header_t
*previous
;
111 * Pointer to next entry in linked list
113 memory_header_t
*next
;
116 * backtrace taken during (re-)allocation
118 backtrace_t
*backtrace
;
121 * Padding to make sizeof(memory_header_t) == 32
123 uint32_t padding
[sizeof(void*) == sizeof(uint32_t) ? 3 : 0];
126 * Number of bytes following after the header
131 * magic bytes to detect bad free or heap underflow, MEMORY_HEADER_MAGIC
135 }__attribute__((__packed__
));
138 * tail appended to each allocated memory block
140 struct memory_tail_t
{
143 * Magic bytes to detect heap overflow, MEMORY_TAIL_MAGIC
147 }__attribute__((__packed__
));
150 * first mem header is just a dummy to chain
151 * the others on it...
153 static memory_header_t first_header
= {
154 .magic
= MEMORY_HEADER_MAGIC
,
158 * Spinlock to access header linked list
160 static spinlock_t
*lock
;
163 * Is leak detection currently enabled?
168 * Whether to report calls to free() with memory not allocated by us
170 static bool ignore_unknown
;
173 * Is leak detection disabled for the current thread?
175 static thread_value_t
*thread_disabled
;
178 * Installs the malloc hooks, enables leak detection
180 static void enable_leak_detective()
186 * Uninstalls the malloc hooks, disables leak detection
188 static void disable_leak_detective()
194 * Enable/Disable leak detective for the current thread
196 * @return Previous value
198 static bool enable_thread(bool enable
)
202 before
= thread_disabled
->get(thread_disabled
) == NULL
;
203 thread_disabled
->set(thread_disabled
, enable
? NULL
: (void*)TRUE
);
208 * Add a header to the beginning of the list
210 static void add_hdr(memory_header_t
*hdr
)
213 hdr
->next
= first_header
.next
;
216 hdr
->next
->previous
= hdr
;
218 hdr
->previous
= &first_header
;
219 first_header
.next
= hdr
;
224 * Remove a header from the list
226 static void remove_hdr(memory_header_t
*hdr
)
231 hdr
->next
->previous
= hdr
->previous
;
233 hdr
->previous
->next
= hdr
->next
;
238 * Check if a header is in the list
240 static bool has_hdr(memory_header_t
*hdr
)
242 memory_header_t
*current
;
246 for (current
= &first_header
; current
!= NULL
; current
= current
->next
)
262 * Copy of original default zone, with functions we call in hooks
264 static malloc_zone_t original
;
267 * Call original malloc()
269 static void* real_malloc(size_t size
)
271 return original
.malloc(malloc_default_zone(), size
);
275 * Call original free()
277 static void real_free(void *ptr
)
279 original
.free(malloc_default_zone(), ptr
);
283 * Call original realloc()
285 static void* real_realloc(void *ptr
, size_t size
)
287 return original
.realloc(malloc_default_zone(), ptr
, size
);
291 * Hook definition: static function with _hook suffix, takes additional zone
293 #define HOOK(ret, name, ...) \
294 static ret name ## _hook(malloc_zone_t *_z, __VA_ARGS__)
297 * forward declaration of hooks
299 HOOK(void*, malloc
, size_t bytes
);
300 HOOK(void*, calloc
, size_t nmemb
, size_t size
);
301 HOOK(void*, valloc
, size_t size
);
302 HOOK(void, free
, void *ptr
);
303 HOOK(void*, realloc
, void *old
, size_t bytes
);
306 * malloc zone size(), must consider the memory header prepended
308 HOOK(size_t, size
, const void *ptr
)
315 before
= enable_thread(FALSE
);
318 ptr
-= sizeof(memory_header_t
);
321 size
= original
.size(malloc_default_zone(), ptr
);
324 enable_thread(before
);
330 * Version of malloc zones we currently support
332 #define MALLOC_ZONE_VERSION 8 /* Snow Leopard */
335 * Hook-in our malloc functions into the default zone
337 static bool register_hooks()
339 static bool once
= FALSE
;
349 zone
= malloc_default_zone();
350 if (zone
->version
!= MALLOC_ZONE_VERSION
)
352 DBG1(DBG_CFG
, "malloc zone version %d unsupported (requiring %d)",
353 zone
->version
, MALLOC_ZONE_VERSION
);
359 page
= (void*)((uintptr_t)zone
/ getpagesize() * getpagesize());
360 if (mprotect(page
, getpagesize(), PROT_WRITE
| PROT_READ
) != 0)
362 DBG1(DBG_CFG
, "malloc zone unprotection failed: %s", strerror(errno
));
366 zone
->size
= size_hook
;
367 zone
->malloc
= malloc_hook
;
368 zone
->calloc
= calloc_hook
;
369 zone
->valloc
= valloc_hook
;
370 zone
->free
= free_hook
;
371 zone
->realloc
= realloc_hook
;
373 /* those other functions can be NULLed out to not use them */
374 zone
->batch_malloc
= NULL
;
375 zone
->batch_free
= NULL
;
376 zone
->memalign
= NULL
;
377 zone
->free_definite_size
= NULL
;
382 #else /* !__APPLE__ */
385 * dlsym() might do a malloc(), but we can't do one before we get the malloc()
386 * function pointer. Use this minimalistic malloc implementation instead.
388 static void* malloc_for_dlsym(size_t size
)
390 static char buf
[1024] = {};
391 static size_t used
= 0;
394 /* roundup to a multiple of 32 */
395 size
= (size
- 1) / 32 * 32 + 32;
397 if (used
+ size
> sizeof(buf
))
407 * Lookup a malloc function, while disabling wrappers
409 static void* get_malloc_fn(char *name
)
416 before
= enable_thread(FALSE
);
418 fn
= dlsym(RTLD_NEXT
, name
);
421 enable_thread(before
);
427 * Call original malloc()
429 static void* real_malloc(size_t size
)
431 static void* (*fn
)(size_t size
);
432 static int recursive
= 0;
436 /* checking recursiveness should actually be thread-specific. But as
437 * it is very likely that the first allocation is done before we go
438 * multi-threaded, we keep it simple. */
441 return malloc_for_dlsym(size
);
444 fn
= get_malloc_fn("malloc");
451 * Call original free()
453 static void real_free(void *ptr
)
455 static void (*fn
)(void *ptr
);
459 fn
= get_malloc_fn("free");
465 * Call original realloc()
467 static void* real_realloc(void *ptr
, size_t size
)
469 static void* (*fn
)(void *ptr
, size_t size
);
473 fn
= get_malloc_fn("realloc");
475 return fn(ptr
, size
);
479 * Hook definition: plain function overloading existing malloc calls
481 #define HOOK(ret, name, ...) ret name(__VA_ARGS__)
484 * Hook initialization when not using hooks, resolve functions.
486 static bool register_hooks()
488 void *buf
= real_malloc(8);
489 buf
= real_realloc(buf
, 16);
494 #endif /* !__APPLE__ */
497 * Leak report white list
499 * List of functions using static allocation buffers or should be suppressed
500 * otherwise on leak report.
502 static char *whitelist
[] = {
503 /* backtraces, including own */
508 "pthread_setspecific",
509 "__pthread_setspecific",
510 /* glibc functions */
524 "register_printf_function",
525 "register_printf_specifier",
541 "_IO_file_doallocate",
542 /* ignore dlopen, as we do not dlclose to get proper leak reports */
547 /* mysql functions */
548 "mysql_init_character_set",
551 /* fastcgi library */
554 "xmlInitCharEncodingHandlers",
560 "soup_message_headers_append",
561 "soup_message_headers_clear",
562 "soup_message_headers_get_list",
563 "soup_message_headers_get_one",
564 "soup_session_abort",
565 "soup_session_get_type",
567 "ldap_int_initialize",
571 "gcrypt_plugin_create",
573 "gcry_check_version",
576 /* OpenSSL: These are needed for unit-tests only, the openssl plugin
577 * does properly clean up any memory during destroy(). */
581 /* OpenSSL 1.1.0 does not cleanup anymore until the library is unloaded */
582 "OPENSSL_init_crypto",
583 "CRYPTO_THREAD_lock_new",
584 "ERR_add_error_data",
586 "ENGINE_load_builtin_engines",
587 "OPENSSL_load_builtin_modules",
588 "CONF_modules_load_file",
591 "SSL_COMP_get_compression_methods",
595 "apr_pool_create_ex",
597 "g_output_stream_write",
598 "g_resolver_lookup_by_name",
599 "g_signal_connect_data",
600 "g_socket_connection_factory_lookup_type",
601 "g_type_init_with_debug_flags",
602 "g_type_register_static",
604 "g_type_create_instance",
605 "g_type_add_interface_static",
606 "g_type_interface_add_prerequisite",
612 "gnutls_global_init",
614 "system__tasking__initialize",
615 "system__tasking__initialization__abort_defer",
616 "system__tasking__stages__create_task",
617 /* in case external threads call into our code */
619 /* FHH IMCs and IMVs */
620 "TNC_IMC_NotifyConnectionChange",
621 "TNC_IMV_NotifyConnectionChange",
623 "botan_public_key_load",
624 "botan_privkey_create_ecdsa",
625 "botan_privkey_create_ecdh",
626 "botan_privkey_load_ecdh",
627 "botan_privkey_load",
631 * Some functions are hard to whitelist, as they don't use a symbol directly.
632 * Use some static initialization to suppress them on leak reports
634 static void init_static_allocations()
641 localtime_r(&t
, &tm
);
645 * Hashtable hash function
647 static u_int
hash(backtrace_t
*key
)
649 enumerator_t
*enumerator
;
653 enumerator
= key
->create_frame_enumerator(key
);
654 while (enumerator
->enumerate(enumerator
, &addr
))
656 hash
= chunk_hash_inc(chunk_from_thing(addr
), hash
);
658 enumerator
->destroy(enumerator
);
664 * Hashtable equals function
666 static bool equals(backtrace_t
*a
, backtrace_t
*b
)
668 return a
->equals(a
, b
);
672 * Summarize and print backtraces
674 static int print_traces(private_leak_detective_t
*this,
675 leak_detective_report_cb_t cb
, void *user
,
676 int thresh
, int thresh_count
,
677 bool detailed
, int *whitelisted
, size_t *sum
)
680 memory_header_t
*hdr
;
681 enumerator_t
*enumerator
;
682 hashtable_t
*entries
;
684 /** associated backtrace */
685 backtrace_t
*backtrace
;
686 /** total size of all allocations */
688 /** number of allocations */
693 before
= enable_thread(FALSE
);
695 entries
= hashtable_create((hashtable_hash_t
)hash
,
696 (hashtable_equals_t
)equals
, 1024);
698 for (hdr
= first_header
.next
; hdr
!= NULL
; hdr
= hdr
->next
)
701 hdr
->backtrace
->contains_function(hdr
->backtrace
,
702 whitelist
, countof(whitelist
)))
707 entry
= entries
->get(entries
, hdr
->backtrace
);
710 entry
->bytes
+= hdr
->bytes
;
716 .backtrace
= hdr
->backtrace
->clone(hdr
->backtrace
),
720 entries
->put(entries
, entry
->backtrace
, entry
);
730 enumerator
= entries
->create_enumerator(entries
);
731 while (enumerator
->enumerate(enumerator
, NULL
, &entry
))
735 if (!thresh
|| entry
->bytes
>= thresh
)
737 if (!thresh_count
|| entry
->count
>= thresh_count
)
739 cb(user
, entry
->count
, entry
->bytes
, entry
->backtrace
,
744 entry
->backtrace
->destroy(entry
->backtrace
);
747 enumerator
->destroy(enumerator
);
748 entries
->destroy(entries
);
750 enable_thread(before
);
754 METHOD(leak_detective_t
, report
, void,
755 private_leak_detective_t
*this, bool detailed
)
757 if (lib
->leak_detective
)
759 int leaks
, whitelisted
= 0;
762 leaks
= print_traces(this, this->report_cb
, this->report_data
,
763 0, 0, detailed
, &whitelisted
, &sum
);
764 if (this->report_scb
)
766 this->report_scb(this->report_data
, leaks
, sum
, whitelisted
);
771 METHOD(leak_detective_t
, set_report_cb
, void,
772 private_leak_detective_t
*this, leak_detective_report_cb_t cb
,
773 leak_detective_summary_cb_t scb
, void *user
)
775 this->report_cb
= cb
;
776 this->report_scb
= scb
;
777 this->report_data
= user
;
780 METHOD(leak_detective_t
, leaks
, int,
781 private_leak_detective_t
*this)
785 return print_traces(this, NULL
, NULL
, 0, 0, FALSE
, &whitelisted
, NULL
);
788 METHOD(leak_detective_t
, set_state
, bool,
789 private_leak_detective_t
*this, bool enable
)
791 return enable_thread(enable
);
794 METHOD(leak_detective_t
, usage
, void,
795 private_leak_detective_t
*this, leak_detective_report_cb_t cb
,
796 leak_detective_summary_cb_t scb
, void *user
)
799 int thresh
, thresh_count
, leaks
, whitelisted
= 0;
802 thresh
= lib
->settings
->get_int(lib
->settings
,
803 "%s.leak_detective.usage_threshold", 10240, lib
->ns
);
804 thresh_count
= lib
->settings
->get_int(lib
->settings
,
805 "%s.leak_detective.usage_threshold_count", 0, lib
->ns
);
806 detailed
= lib
->settings
->get_bool(lib
->settings
,
807 "%s.leak_detective.detailed", TRUE
, lib
->ns
);
809 leaks
= print_traces(this, cb
, user
, thresh
, thresh_count
,
810 detailed
, &whitelisted
, &sum
);
813 scb(user
, leaks
, sum
, whitelisted
);
818 * Wrapped malloc() function
820 HOOK(void*, malloc
, size_t bytes
)
822 memory_header_t
*hdr
;
826 if (!enabled
|| thread_disabled
->get(thread_disabled
))
828 return real_malloc(bytes
);
831 hdr
= real_malloc(sizeof(memory_header_t
) + bytes
+ sizeof(memory_tail_t
));
832 tail
= ((void*)hdr
) + bytes
+ sizeof(memory_header_t
);
833 /* set to something which causes crashes */
834 memset(hdr
, MEMORY_ALLOC_PATTERN
,
835 sizeof(memory_header_t
) + bytes
+ sizeof(memory_tail_t
));
837 before
= enable_thread(FALSE
);
838 hdr
->backtrace
= backtrace_create(2);
839 enable_thread(before
);
841 hdr
->magic
= MEMORY_HEADER_MAGIC
;
843 tail
->magic
= MEMORY_TAIL_MAGIC
;
851 * Wrapped calloc() function
853 HOOK(void*, calloc
, size_t nmemb
, size_t size
)
856 volatile size_t total
;
858 total
= nmemb
* size
;
860 memset(ptr
, 0, total
);
866 * Wrapped valloc(), TODO: currently not supported
868 HOOK(void*, valloc
, size_t size
)
870 DBG1(DBG_LIB
, "valloc() used, but leak-detective hook missing");
875 * Wrapped free() function
877 HOOK(void, free
, void *ptr
)
879 memory_header_t
*hdr
;
881 backtrace_t
*backtrace
;
884 if (!enabled
|| thread_disabled
->get(thread_disabled
))
886 /* after deinitialization we might have to free stuff we allocated
887 * while we were enabled */
888 if (!first_header
.magic
&& ptr
)
890 hdr
= ptr
- sizeof(memory_header_t
);
891 tail
= ptr
+ hdr
->bytes
;
892 if (hdr
->magic
== MEMORY_HEADER_MAGIC
&&
893 tail
->magic
== MEMORY_TAIL_MAGIC
)
901 /* allow freeing of NULL */
906 hdr
= ptr
- sizeof(memory_header_t
);
907 tail
= ptr
+ hdr
->bytes
;
909 before
= enable_thread(FALSE
);
910 if (hdr
->magic
!= MEMORY_HEADER_MAGIC
||
911 tail
->magic
!= MEMORY_TAIL_MAGIC
)
915 /* check if memory appears to be allocated by our hooks */
918 fprintf(stderr
, "freeing corrupted memory (%p): "
919 "%u bytes, header magic 0x%x, tail magic 0x%x:\n",
920 ptr
, hdr
->bytes
, hdr
->magic
, tail
->magic
);
923 if (hdr
->magic
== MEMORY_HEADER_MAGIC
)
924 { /* only access the old backtrace if header magic is valid */
925 hdr
->backtrace
->log(hdr
->backtrace
, stderr
, TRUE
);
926 hdr
->backtrace
->destroy(hdr
->backtrace
);
930 fprintf(stderr
, " header magic invalid, ignore backtrace of "
936 /* just free this block of unknown memory */
945 fprintf(stderr
, "freeing unknown memory (%p):\n", ptr
);
950 backtrace
= backtrace_create(2);
951 backtrace
->log(backtrace
, stderr
, TRUE
);
952 backtrace
->destroy(backtrace
);
959 hdr
->backtrace
->destroy(hdr
->backtrace
);
961 /* set mem to something remarkable */
962 memset(hdr
, MEMORY_FREE_PATTERN
,
963 sizeof(memory_header_t
) + hdr
->bytes
+ sizeof(memory_tail_t
));
966 enable_thread(before
);
970 * Wrapped realloc() function
972 HOOK(void*, realloc
, void *old
, size_t bytes
)
974 memory_header_t
*hdr
;
976 backtrace_t
*backtrace
;
977 bool before
, have_backtrace
= TRUE
;
979 if (!enabled
|| thread_disabled
->get(thread_disabled
))
981 return real_realloc(old
, bytes
);
983 /* allow reallocation of NULL */
986 return malloc(bytes
);
988 /* handle zero size as a free() */
995 hdr
= old
- sizeof(memory_header_t
);
996 tail
= old
+ hdr
->bytes
;
998 before
= enable_thread(FALSE
);
999 if (hdr
->magic
!= MEMORY_HEADER_MAGIC
||
1000 tail
->magic
!= MEMORY_TAIL_MAGIC
)
1004 /* check if memory appears to be allocated by our hooks */
1007 fprintf(stderr
, "reallocating corrupted memory (%p, %u bytes): "
1008 "%zu bytes, header magic 0x%x, tail magic 0x%x:\n",
1009 old
, hdr
->bytes
, bytes
, hdr
->magic
, tail
->magic
);
1012 if (hdr
->magic
== MEMORY_HEADER_MAGIC
)
1013 { /* only access header fields (backtrace, bytes) if header magic
1015 hdr
->backtrace
->log(hdr
->backtrace
, stderr
, TRUE
);
1016 memset(&tail
->magic
, MEMORY_ALLOC_PATTERN
, sizeof(tail
->magic
));
1020 fprintf(stderr
, " header magic invalid, ignore backtrace of "
1022 have_backtrace
= FALSE
;
1023 hdr
->magic
= MEMORY_HEADER_MAGIC
;
1028 /* adopt this block of unknown memory */
1030 have_backtrace
= FALSE
;
1038 fprintf(stderr
, "reallocating unknown memory (%p): %zu bytes:\n",
1044 backtrace
= backtrace_create(2);
1045 backtrace
->log(backtrace
, stderr
, TRUE
);
1046 backtrace
->destroy(backtrace
);
1052 /* clear tail magic, allocate, set tail magic */
1053 memset(&tail
->magic
, MEMORY_ALLOC_PATTERN
, sizeof(tail
->magic
));
1056 hdr
= real_realloc(hdr
,
1057 sizeof(memory_header_t
) + bytes
+ sizeof(memory_tail_t
));
1058 tail
= ((void*)hdr
) + bytes
+ sizeof(memory_header_t
);
1059 tail
->magic
= MEMORY_TAIL_MAGIC
;
1061 /* update statistics */
1066 hdr
->backtrace
->destroy(hdr
->backtrace
);
1068 hdr
->backtrace
= backtrace_create(2);
1069 enable_thread(before
);
1076 METHOD(leak_detective_t
, destroy
, void,
1077 private_leak_detective_t
*this)
1079 disable_leak_detective();
1080 lock
->destroy(lock
);
1081 thread_disabled
->destroy(thread_disabled
);
1083 first_header
.magic
= 0;
1084 first_header
.next
= NULL
;
1090 leak_detective_t
*leak_detective_create()
1092 private_leak_detective_t
*this;
1097 .set_report_cb
= _set_report_cb
,
1100 .set_state
= _set_state
,
1101 .destroy
= _destroy
,
1105 if (getenv("LEAK_DETECTIVE_DISABLE") != NULL
)
1110 ignore_unknown
= getenv("LEAK_DETECTIVE_IGNORE_UNKNOWN") != NULL
;
1112 lock
= spinlock_create();
1113 thread_disabled
= thread_value_create(NULL
);
1115 init_static_allocations();
1117 if (register_hooks())
1119 enable_leak_detective();
1121 return &this->public;