2 * Copyright (C) 2013-2018 Tobias Brunner
3 * Copyright (C) 2006-2013 Martin Willi
5 * Copyright (C) secunet Security Networks AG
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
33 #include <malloc/malloc.h>
34 /* overload some of our types clashing with mach */
35 #define host_t strongswan_host_t
36 #define processor_t strongswan_processor_t
37 #define thread_t strongswan_thread_t
38 #endif /* __APPLE__ */
40 #include "leak_detective.h"
43 #include <utils/utils.h>
44 #include <utils/debug.h>
45 #include <utils/backtrace.h>
46 #include <collections/hashtable.h>
47 #include <threading/thread_value.h>
48 #include <threading/spinlock.h>
50 typedef struct private_leak_detective_t private_leak_detective_t
;
53 * private data of leak_detective
55 struct private_leak_detective_t
{
60 leak_detective_t
public;
63 * Registered report() function
65 leak_detective_report_cb_t report_cb
;
68 * Registered report() summary function
70 leak_detective_summary_cb_t report_scb
;
73 * Registered user data for callbacks
79 * Magic value which helps to detect memory corruption. Yummy!
81 #define MEMORY_HEADER_MAGIC 0x7ac0be11
84 * Magic written to tail of allocation
86 #define MEMORY_TAIL_MAGIC 0xcafebabe
89 * Pattern which is filled in memory before freeing it
91 #define MEMORY_FREE_PATTERN 0xFF
94 * Pattern which is filled in newly allocated memory
96 #define MEMORY_ALLOC_PATTERN 0xEE
98 typedef struct memory_header_t memory_header_t
;
99 typedef struct memory_tail_t memory_tail_t
;
102 * Header which is prepended to each allocated memory block
104 struct memory_header_t
{
107 * Pointer to previous entry in linked list
109 memory_header_t
*previous
;
112 * Pointer to next entry in linked list
114 memory_header_t
*next
;
117 * backtrace taken during (re-)allocation
119 backtrace_t
*backtrace
;
122 * Padding to make sizeof(memory_header_t) == 32
124 uint32_t padding
[sizeof(void*) == sizeof(uint32_t) ? 3 : 0];
127 * Number of bytes following after the header
132 * magic bytes to detect bad free or heap underflow, MEMORY_HEADER_MAGIC
136 }__attribute__((__packed__
));
139 * tail appended to each allocated memory block
141 struct memory_tail_t
{
144 * Magic bytes to detect heap overflow, MEMORY_TAIL_MAGIC
148 }__attribute__((__packed__
));
151 * first mem header is just a dummy to chain
152 * the others on it...
154 static memory_header_t first_header
= {
155 .magic
= MEMORY_HEADER_MAGIC
,
159 * Spinlock to access header linked list
161 static spinlock_t
*lock
;
164 * Is leak detection currently enabled?
169 * Whether to report calls to free() with memory not allocated by us
171 static bool ignore_unknown
;
174 * Is leak detection disabled for the current thread?
176 static thread_value_t
*thread_disabled
;
179 * Installs the malloc hooks, enables leak detection
181 static void enable_leak_detective()
187 * Uninstalls the malloc hooks, disables leak detection
189 static void disable_leak_detective()
195 * Enable/Disable leak detective for the current thread
197 * @return Previous value
199 static bool enable_thread(bool enable
)
203 before
= thread_disabled
->get(thread_disabled
) == NULL
;
204 thread_disabled
->set(thread_disabled
, enable
? NULL
: (void*)TRUE
);
209 * Add a header to the beginning of the list
211 static void add_hdr(memory_header_t
*hdr
)
214 hdr
->next
= first_header
.next
;
217 hdr
->next
->previous
= hdr
;
219 hdr
->previous
= &first_header
;
220 first_header
.next
= hdr
;
225 * Remove a header from the list
227 static void remove_hdr(memory_header_t
*hdr
)
232 hdr
->next
->previous
= hdr
->previous
;
234 hdr
->previous
->next
= hdr
->next
;
239 * Check if a header is in the list
241 static bool has_hdr(memory_header_t
*hdr
)
243 memory_header_t
*current
;
247 for (current
= &first_header
; current
!= NULL
; current
= current
->next
)
263 * Copy of original default zone, with functions we call in hooks
265 static malloc_zone_t original
;
268 * Call original malloc()
270 static void* real_malloc(size_t size
)
272 return original
.malloc(malloc_default_zone(), size
);
276 * Call original free()
278 static void real_free(void *ptr
)
280 original
.free(malloc_default_zone(), ptr
);
284 * Call original realloc()
286 static void* real_realloc(void *ptr
, size_t size
)
288 return original
.realloc(malloc_default_zone(), ptr
, size
);
292 * Hook definition: static function with _hook suffix, takes additional zone
294 #define HOOK(ret, name, ...) \
295 static ret name ## _hook(malloc_zone_t *_z, __VA_ARGS__)
298 * forward declaration of hooks
300 HOOK(void*, malloc
, size_t bytes
);
301 HOOK(void*, calloc
, size_t nmemb
, size_t size
);
302 HOOK(void*, valloc
, size_t size
);
303 HOOK(void, free
, void *ptr
);
304 HOOK(void*, realloc
, void *old
, size_t bytes
);
307 * malloc zone size(), must consider the memory header prepended
309 HOOK(size_t, size
, const void *ptr
)
316 before
= enable_thread(FALSE
);
319 ptr
-= sizeof(memory_header_t
);
322 size
= original
.size(malloc_default_zone(), ptr
);
325 enable_thread(before
);
331 * Version of malloc zones we currently support
333 #define MALLOC_ZONE_VERSION 8 /* Snow Leopard */
336 * Hook-in our malloc functions into the default zone
338 static bool register_hooks()
340 static bool once
= FALSE
;
350 zone
= malloc_default_zone();
351 if (zone
->version
!= MALLOC_ZONE_VERSION
)
353 DBG1(DBG_CFG
, "malloc zone version %d unsupported (requiring %d)",
354 zone
->version
, MALLOC_ZONE_VERSION
);
360 page
= (void*)((uintptr_t)zone
/ getpagesize() * getpagesize());
361 if (mprotect(page
, getpagesize(), PROT_WRITE
| PROT_READ
) != 0)
363 DBG1(DBG_CFG
, "malloc zone unprotection failed: %s", strerror(errno
));
367 zone
->size
= size_hook
;
368 zone
->malloc
= malloc_hook
;
369 zone
->calloc
= calloc_hook
;
370 zone
->valloc
= valloc_hook
;
371 zone
->free
= free_hook
;
372 zone
->realloc
= realloc_hook
;
374 /* those other functions can be NULLed out to not use them */
375 zone
->batch_malloc
= NULL
;
376 zone
->batch_free
= NULL
;
377 zone
->memalign
= NULL
;
378 zone
->free_definite_size
= NULL
;
383 #else /* !__APPLE__ */
386 * dlsym() might do a malloc(), but we can't do one before we get the malloc()
387 * function pointer. Use this minimalistic malloc implementation instead.
389 static void* malloc_for_dlsym(size_t size
)
391 static char buf
[1024] = {};
392 static size_t used
= 0;
395 /* roundup to a multiple of 32 */
396 size
= (size
- 1) / 32 * 32 + 32;
398 if (used
+ size
> sizeof(buf
))
408 * Lookup a malloc function, while disabling wrappers
410 static void* get_malloc_fn(char *name
)
417 before
= enable_thread(FALSE
);
419 fn
= dlsym(RTLD_NEXT
, name
);
422 enable_thread(before
);
428 * Call original malloc()
430 static void* real_malloc(size_t size
)
432 static void* (*fn
)(size_t size
);
433 static int recursive
= 0;
437 /* checking recursiveness should actually be thread-specific. But as
438 * it is very likely that the first allocation is done before we go
439 * multi-threaded, we keep it simple. */
442 return malloc_for_dlsym(size
);
445 fn
= get_malloc_fn("malloc");
452 * Call original free()
454 static void real_free(void *ptr
)
456 static void (*fn
)(void *ptr
);
460 fn
= get_malloc_fn("free");
466 * Call original realloc()
468 static void* real_realloc(void *ptr
, size_t size
)
470 static void* (*fn
)(void *ptr
, size_t size
);
474 fn
= get_malloc_fn("realloc");
476 return fn(ptr
, size
);
480 * Hook definition: plain function overloading existing malloc calls
482 #define HOOK(ret, name, ...) ret name(__VA_ARGS__)
485 * Hook initialization when not using hooks, resolve functions.
487 static bool register_hooks()
489 void *buf
= real_malloc(8);
490 buf
= real_realloc(buf
, 16);
495 #endif /* !__APPLE__ */
498 * Leak report white list
500 * List of functions using static allocation buffers or should be suppressed
501 * otherwise on leak report.
503 static char *whitelist
[] = {
504 /* backtraces, including own */
509 "pthread_setspecific",
510 "__pthread_setspecific",
511 /* glibc functions */
525 "register_printf_function",
526 "register_printf_specifier",
542 "_IO_file_doallocate",
543 "selinux_check_access",
544 /* ignore dlopen, as we do not dlclose to get proper leak reports */
549 /* mysql functions */
550 "mysql_init_character_set",
553 /* fastcgi library */
556 "xmlInitCharEncodingHandlers",
563 "soup_headers_parse_response",
564 "soup_message_headers_append",
565 "soup_message_headers_clear",
566 "soup_message_headers_get_list",
567 "soup_message_headers_get_one",
568 "soup_session_abort",
569 "soup_session_get_type",
570 "soup_session_remove_feature",
572 "ldap_int_initialize",
576 "gcrypt_plugin_create",
578 "gcry_check_version",
581 /* OpenSSL: These are needed for unit-tests only, the openssl plugin
582 * does properly clean up any memory during destroy(). */
586 /* OpenSSL 1.1.0 does not cleanup anymore until the library is unloaded */
587 "OPENSSL_init_crypto",
589 "CRYPTO_THREAD_lock_new",
590 "ERR_add_error_data",
592 "ENGINE_load_builtin_engines",
593 "OPENSSL_load_builtin_modules",
594 "CONF_modules_load_file",
597 "RAND_DRBG_generate",
598 "RAND_DRBG_get0_master",
599 "RAND_DRBG_get0_private",
600 "RAND_DRBG_get0_public",
601 /* OpenSSL 3.0 caches even more static stuff */
604 "EVP_DigestSignInit",
605 "EVP_DigestVerifyInit",
606 "EVP_PKEY_encrypt_init",
607 "EVP_PKEY_decrypt_init",
608 "EVP_PKEY_derive_init",
609 "EVP_PKEY_sign_init",
610 "EVP_ASYM_CIPHER_fetch",
617 "EVP_SIGNATURE_fetch",
618 "OSSL_DECODER_do_all_provided",
619 "OSSL_ENCODER_do_all_provided",
620 "OSSL_PROVIDER_try_load",
621 "OSSL_PROVIDER_load",
624 /* We get this via libcurl and OpenSSL 1.1.1 */
625 "CRYPTO_get_ex_new_index",
627 "SSL_COMP_get_compression_methods",
631 "apr_pool_create_ex",
633 "g_output_stream_write",
634 "g_resolver_lookup_by_name",
635 "g_signal_connect_data",
636 "g_socket_connection_factory_lookup_type",
637 "g_type_init_with_debug_flags",
638 "g_type_register_static",
640 "g_type_create_instance",
641 "g_type_add_interface_static",
642 "g_type_interface_add_prerequisite",
648 "gnutls_global_init",
650 "system__tasking__initialize",
651 "system__tasking__initialization__abort_defer",
652 "system__tasking__stages__create_task",
653 "system__task_primitives__operations__register_foreign_thread__2",
654 /* in case external threads call into our code */
656 /* FHH IMCs and IMVs */
657 "TNC_IMC_NotifyConnectionChange",
658 "TNC_IMV_NotifyConnectionChange",
660 "botan_public_key_load",
661 "botan_privkey_create",
662 "botan_privkey_load_ecdh",
663 "botan_privkey_load",
668 * Some functions are hard to whitelist, as they don't use a symbol directly.
669 * Use some static initialization to suppress them on leak reports
671 static void init_static_allocations()
678 localtime_r(&t
, &tm
);
682 * Hashtable hash function
684 static u_int
hash(backtrace_t
*key
)
686 enumerator_t
*enumerator
;
690 enumerator
= key
->create_frame_enumerator(key
);
691 while (enumerator
->enumerate(enumerator
, &addr
))
693 hash
= chunk_hash_inc(chunk_from_thing(addr
), hash
);
695 enumerator
->destroy(enumerator
);
701 * Hashtable equals function
703 static bool equals(backtrace_t
*a
, backtrace_t
*b
)
705 return a
->equals(a
, b
);
709 * Summarize and print backtraces
711 static int print_traces(private_leak_detective_t
*this,
712 leak_detective_report_cb_t cb
, void *user
,
713 int thresh
, int thresh_count
,
714 bool detailed
, int *whitelisted
, size_t *sum
)
717 memory_header_t
*hdr
;
718 enumerator_t
*enumerator
;
719 hashtable_t
*entries
, *ignored
= NULL
;
722 /** associated backtrace */
723 backtrace_t
*backtrace
;
724 /** total size of all allocations */
726 /** number of allocations */
731 before
= enable_thread(FALSE
);
733 entries
= hashtable_create((hashtable_hash_t
)hash
,
734 (hashtable_equals_t
)equals
, 1024);
737 ignored
= hashtable_create((hashtable_hash_t
)hash
,
738 (hashtable_equals_t
)equals
, 1024);
742 for (hdr
= first_header
.next
; hdr
!= NULL
; hdr
= hdr
->next
)
746 bt
= ignored
->get(ignored
, hdr
->backtrace
);
749 if (hdr
->backtrace
->contains_function(hdr
->backtrace
, whitelist
,
753 ignored
->put(ignored
, bt
, bt
);
762 entry
= entries
->get(entries
, hdr
->backtrace
);
765 entry
->bytes
+= hdr
->bytes
;
771 .backtrace
= hdr
->backtrace
->clone(hdr
->backtrace
),
775 entries
->put(entries
, entry
->backtrace
, entry
);
786 enumerator
= entries
->create_enumerator(entries
);
787 while (enumerator
->enumerate(enumerator
, NULL
, &entry
))
791 if (!thresh
|| entry
->bytes
>= thresh
)
793 if (!thresh_count
|| entry
->count
>= thresh_count
)
795 cb(user
, entry
->count
, entry
->bytes
, entry
->backtrace
,
800 entry
->backtrace
->destroy(entry
->backtrace
);
803 enumerator
->destroy(enumerator
);
804 entries
->destroy(entries
);
806 enable_thread(before
);
810 METHOD(leak_detective_t
, report
, void,
811 private_leak_detective_t
*this, bool detailed
)
813 if (lib
->leak_detective
)
815 int leaks
, whitelisted
= 0;
818 leaks
= print_traces(this, this->report_cb
, this->report_data
,
819 0, 0, detailed
, &whitelisted
, &sum
);
820 if (this->report_scb
)
822 this->report_scb(this->report_data
, leaks
, sum
, whitelisted
);
827 METHOD(leak_detective_t
, set_report_cb
, void,
828 private_leak_detective_t
*this, leak_detective_report_cb_t cb
,
829 leak_detective_summary_cb_t scb
, void *user
)
831 this->report_cb
= cb
;
832 this->report_scb
= scb
;
833 this->report_data
= user
;
836 METHOD(leak_detective_t
, leaks
, int,
837 private_leak_detective_t
*this)
841 return print_traces(this, NULL
, NULL
, 0, 0, FALSE
, &whitelisted
, NULL
);
844 METHOD(leak_detective_t
, set_state
, bool,
845 private_leak_detective_t
*this, bool enable
)
847 return enable_thread(enable
);
850 METHOD(leak_detective_t
, usage
, void,
851 private_leak_detective_t
*this, leak_detective_report_cb_t cb
,
852 leak_detective_summary_cb_t scb
, void *user
)
855 int thresh
, thresh_count
, leaks
, whitelisted
= 0;
858 thresh
= lib
->settings
->get_int(lib
->settings
,
859 "%s.leak_detective.usage_threshold", 10240, lib
->ns
);
860 thresh_count
= lib
->settings
->get_int(lib
->settings
,
861 "%s.leak_detective.usage_threshold_count", 0, lib
->ns
);
862 detailed
= lib
->settings
->get_bool(lib
->settings
,
863 "%s.leak_detective.detailed", TRUE
, lib
->ns
);
865 leaks
= print_traces(this, cb
, user
, thresh
, thresh_count
,
866 detailed
, &whitelisted
, &sum
);
869 scb(user
, leaks
, sum
, whitelisted
);
874 * Wrapped malloc() function
876 HOOK(void*, malloc
, size_t bytes
)
878 memory_header_t
*hdr
;
882 if (!enabled
|| thread_disabled
->get(thread_disabled
))
884 return real_malloc(bytes
);
887 hdr
= real_malloc(sizeof(memory_header_t
) + bytes
+ sizeof(memory_tail_t
));
888 tail
= ((void*)hdr
) + bytes
+ sizeof(memory_header_t
);
889 /* set to something which causes crashes */
890 memset(hdr
, MEMORY_ALLOC_PATTERN
,
891 sizeof(memory_header_t
) + bytes
+ sizeof(memory_tail_t
));
893 before
= enable_thread(FALSE
);
894 hdr
->backtrace
= backtrace_create(2);
895 enable_thread(before
);
897 hdr
->magic
= MEMORY_HEADER_MAGIC
;
899 tail
->magic
= MEMORY_TAIL_MAGIC
;
907 * Wrapped calloc() function
909 HOOK(void*, calloc
, size_t nmemb
, size_t size
)
912 volatile size_t total
;
914 total
= nmemb
* size
;
916 memset(ptr
, 0, total
);
922 * Wrapped valloc(), TODO: currently not supported
924 HOOK(void*, valloc
, size_t size
)
926 DBG1(DBG_LIB
, "valloc() used, but leak-detective hook missing");
931 * Wrapped free() function
933 HOOK(void, free
, void *ptr
)
935 memory_header_t
*hdr
;
937 backtrace_t
*backtrace
;
940 if (!enabled
|| thread_disabled
->get(thread_disabled
))
942 /* after deinitialization we might have to free stuff we allocated
943 * while we were enabled */
944 if (!first_header
.magic
&& ptr
)
946 hdr
= ptr
- sizeof(memory_header_t
);
947 tail
= ptr
+ hdr
->bytes
;
948 if (hdr
->magic
== MEMORY_HEADER_MAGIC
&&
949 tail
->magic
== MEMORY_TAIL_MAGIC
)
957 /* allow freeing of NULL */
962 hdr
= ptr
- sizeof(memory_header_t
);
963 tail
= ptr
+ hdr
->bytes
;
965 before
= enable_thread(FALSE
);
966 if (hdr
->magic
!= MEMORY_HEADER_MAGIC
||
967 tail
->magic
!= MEMORY_TAIL_MAGIC
)
971 /* check if memory appears to be allocated by our hooks */
974 fprintf(stderr
, "freeing corrupted memory (%p): "
975 "%u bytes, header magic 0x%x, tail magic 0x%x:\n",
976 ptr
, hdr
->bytes
, hdr
->magic
, tail
->magic
);
979 if (hdr
->magic
== MEMORY_HEADER_MAGIC
)
980 { /* only access the old backtrace if header magic is valid */
981 hdr
->backtrace
->log(hdr
->backtrace
, stderr
, TRUE
);
982 hdr
->backtrace
->destroy(hdr
->backtrace
);
986 fprintf(stderr
, " header magic invalid, ignore backtrace of "
992 /* just free this block of unknown memory */
1001 fprintf(stderr
, "freeing unknown memory (%p):\n", ptr
);
1006 backtrace
= backtrace_create(2);
1007 backtrace
->log(backtrace
, stderr
, TRUE
);
1008 backtrace
->destroy(backtrace
);
1015 hdr
->backtrace
->destroy(hdr
->backtrace
);
1017 /* set mem to something remarkable */
1018 memset(hdr
, MEMORY_FREE_PATTERN
,
1019 sizeof(memory_header_t
) + hdr
->bytes
+ sizeof(memory_tail_t
));
1022 enable_thread(before
);
1026 * Wrapped realloc() function
1028 HOOK(void*, realloc
, void *old
, size_t bytes
)
1030 memory_header_t
*hdr
;
1031 memory_tail_t
*tail
;
1032 backtrace_t
*backtrace
;
1033 bool before
, have_backtrace
= TRUE
;
1035 if (!enabled
|| thread_disabled
->get(thread_disabled
))
1037 return real_realloc(old
, bytes
);
1039 /* allow reallocation of NULL */
1042 return malloc(bytes
);
1044 /* handle zero size as a free() */
1051 hdr
= old
- sizeof(memory_header_t
);
1052 tail
= old
+ hdr
->bytes
;
1054 before
= enable_thread(FALSE
);
1055 if (hdr
->magic
!= MEMORY_HEADER_MAGIC
||
1056 tail
->magic
!= MEMORY_TAIL_MAGIC
)
1060 /* check if memory appears to be allocated by our hooks */
1063 fprintf(stderr
, "reallocating corrupted memory (%p, %u bytes): "
1064 "%zu bytes, header magic 0x%x, tail magic 0x%x:\n",
1065 old
, hdr
->bytes
, bytes
, hdr
->magic
, tail
->magic
);
1068 if (hdr
->magic
== MEMORY_HEADER_MAGIC
)
1069 { /* only access header fields (backtrace, bytes) if header magic
1071 hdr
->backtrace
->log(hdr
->backtrace
, stderr
, TRUE
);
1072 memset(&tail
->magic
, MEMORY_ALLOC_PATTERN
, sizeof(tail
->magic
));
1076 fprintf(stderr
, " header magic invalid, ignore backtrace of "
1078 have_backtrace
= FALSE
;
1079 hdr
->magic
= MEMORY_HEADER_MAGIC
;
1084 /* adopt this block of unknown memory */
1086 have_backtrace
= FALSE
;
1094 fprintf(stderr
, "reallocating unknown memory (%p): %zu bytes:\n",
1100 backtrace
= backtrace_create(2);
1101 backtrace
->log(backtrace
, stderr
, TRUE
);
1102 backtrace
->destroy(backtrace
);
1108 /* clear tail magic, allocate, set tail magic */
1109 memset(&tail
->magic
, MEMORY_ALLOC_PATTERN
, sizeof(tail
->magic
));
1112 hdr
= real_realloc(hdr
,
1113 sizeof(memory_header_t
) + bytes
+ sizeof(memory_tail_t
));
1114 tail
= ((void*)hdr
) + bytes
+ sizeof(memory_header_t
);
1115 tail
->magic
= MEMORY_TAIL_MAGIC
;
1117 /* update statistics */
1122 hdr
->backtrace
->destroy(hdr
->backtrace
);
1124 hdr
->backtrace
= backtrace_create(2);
1125 enable_thread(before
);
1132 METHOD(leak_detective_t
, destroy
, void,
1133 private_leak_detective_t
*this)
1135 disable_leak_detective();
1136 lock
->destroy(lock
);
1137 thread_disabled
->destroy(thread_disabled
);
1139 first_header
.magic
= 0;
1140 first_header
.next
= NULL
;
1146 leak_detective_t
*leak_detective_create()
1148 private_leak_detective_t
*this;
1153 .set_report_cb
= _set_report_cb
,
1156 .set_state
= _set_state
,
1157 .destroy
= _destroy
,
1161 if (getenv("LEAK_DETECTIVE_DISABLE") != NULL
)
1166 ignore_unknown
= getenv("LEAK_DETECTIVE_IGNORE_UNKNOWN") != NULL
;
1168 lock
= spinlock_create();
1169 thread_disabled
= thread_value_create(NULL
);
1171 init_static_allocations();
1173 if (register_hooks())
1175 enable_leak_detective();
1177 return &this->public;