2 * Copyright (C) 2013 Tobias Brunner
3 * Copyright (C) 2006-2013 Martin Willi
4 * 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
22 #include <sys/socket.h>
23 #include <netinet/in.h>
24 #include <arpa/inet.h>
32 #include "leak_detective.h"
35 #include <utils/debug.h>
36 #include <utils/backtrace.h>
37 #include <collections/hashtable.h>
38 #include <threading/thread_value.h>
39 #include <threading/spinlock.h>
41 typedef struct private_leak_detective_t private_leak_detective_t
;
44 * private data of leak_detective
46 struct private_leak_detective_t
{
51 leak_detective_t
public;
55 * Magic value which helps to detect memory corruption. Yummy!
57 #define MEMORY_HEADER_MAGIC 0x7ac0be11
60 * Magic written to tail of allocation
62 #define MEMORY_TAIL_MAGIC 0xcafebabe
65 * Pattern which is filled in memory before freeing it
67 #define MEMORY_FREE_PATTERN 0xFF
70 * Pattern which is filled in newly allocated memory
72 #define MEMORY_ALLOC_PATTERN 0xEE
74 static u_int count_malloc
= 0;
75 static u_int count_free
= 0;
76 static u_int count_realloc
= 0;
78 typedef struct memory_header_t memory_header_t
;
79 typedef struct memory_tail_t memory_tail_t
;
82 * Header which is prepended to each allocated memory block
84 struct memory_header_t
{
87 * Pointer to previous entry in linked list
89 memory_header_t
*previous
;
92 * Pointer to next entry in linked list
94 memory_header_t
*next
;
97 * backtrace taken during (re-)allocation
99 backtrace_t
*backtrace
;
102 * Padding to make sizeof(memory_header_t) == 32
104 u_int32_t padding
[sizeof(void*) == sizeof(u_int32_t
) ?
3 : 0];
107 * Number of bytes following after the header
112 * magic bytes to detect bad free or heap underflow, MEMORY_HEADER_MAGIC
116 }__attribute__((__packed__
));
119 * tail appended to each allocated memory block
121 struct memory_tail_t
{
124 * Magic bytes to detect heap overflow, MEMORY_TAIL_MAGIC
128 }__attribute__((__packed__
));
131 * first mem header is just a dummy to chain
132 * the others on it...
134 static memory_header_t first_header
= {
135 .magic
= MEMORY_HEADER_MAGIC
,
139 * Spinlock to access header linked list
141 static spinlock_t
*lock
;
144 * Is leak detection currently enabled?
146 static bool enabled
= FALSE
;
149 * Is leak detection disabled for the current thread?
151 static thread_value_t
*thread_disabled
;
154 * Installs the malloc hooks, enables leak detection
156 static void enable_leak_detective()
162 * Uninstalls the malloc hooks, disables leak detection
164 static void disable_leak_detective()
170 * Enable/Disable leak detective for the current thread
172 * @return Previous value
174 static bool enable_thread(bool enable
)
178 before
= thread_disabled
->get(thread_disabled
) == NULL
;
179 thread_disabled
->set(thread_disabled
, enable ? NULL
: (void*)TRUE
);
184 * dlsym() might do a malloc(), but we can't do one before we get the malloc()
185 * function pointer. Use this minimalistic malloc implementation instead.
187 static void* malloc_for_dlsym(size_t size
)
189 static char buf
[1024] = {};
190 static size_t used
= 0;
193 /* roundup to a multiple of 32 */
194 size
= (size
- 1) / 32 * 32 + 32;
196 if (used
+ size
> sizeof(buf
))
206 * Lookup a malloc function, while disabling wrappers
208 static void* get_malloc_fn(char *name
)
215 before
= enable_thread(FALSE
);
217 fn
= dlsym(RTLD_NEXT
, name
);
220 enable_thread(before
);
226 * Call original malloc()
228 static void* real_malloc(size_t size
)
230 static void* (*fn
)(size_t size
);
231 static int recursive
= 0;
235 /* checking recursiveness should actually be thread-specific. But as
236 * it is very likely that the first allocation is done before we go
237 * multi-threaded, we keep it simple. */
240 return malloc_for_dlsym(size
);
243 fn
= get_malloc_fn("malloc");
250 * Call original free()
252 static void real_free(void *ptr
)
254 static void (*fn
)(void *ptr
);
258 fn
= get_malloc_fn("free");
264 * Call original realloc()
266 static void* real_realloc(void *ptr
, size_t size
)
268 static void* (*fn
)(void *ptr
, size_t size
);
272 fn
= get_malloc_fn("realloc");
274 return fn(ptr
, size
);
278 * Leak report white list
280 * List of functions using static allocation buffers or should be suppressed
281 * otherwise on leak report.
283 char *whitelist
[] = {
284 /* backtraces, including own */
289 "pthread_setspecific",
290 "__pthread_setspecific",
291 /* glibc functions */
305 "register_printf_function",
306 "register_printf_specifier",
320 /* ignore dlopen, as we do not dlclose to get proper leak reports */
325 /* mysql functions */
326 "mysql_init_character_set",
329 /* fastcgi library */
332 "xmlInitCharEncodingHandlers",
342 "ENGINE_load_builtin_engines",
348 "gcry_check_version",
354 "apr_pool_create_ex",
356 "g_type_init_with_debug_flags",
357 "g_type_register_static",
359 "g_type_create_instance",
360 "g_type_add_interface_static",
361 "g_type_interface_add_prerequisite",
362 "g_socket_connection_factory_lookup_type",
366 "gnutls_global_init",
370 * Some functions are hard to whitelist, as they don't use a symbol directly.
371 * Use some static initialization to suppress them on leak reports
373 static void init_static_allocations()
379 * Hashtable hash function
381 static u_int
hash(backtrace_t
*key
)
383 enumerator_t
*enumerator
;
387 enumerator
= key
->create_frame_enumerator(key
);
388 while (enumerator
->enumerate(enumerator
, &addr
))
390 hash
= chunk_hash_inc(chunk_from_thing(addr
), hash
);
392 enumerator
->destroy(enumerator
);
398 * Hashtable equals function
400 static bool equals(backtrace_t
*a
, backtrace_t
*b
)
402 return a
->equals(a
, b
);
406 * Summarize and print backtraces
408 static int print_traces(private_leak_detective_t
*this,
409 FILE *out
, int thresh
, bool detailed
, int *whitelisted
)
412 memory_header_t
*hdr
;
413 enumerator_t
*enumerator
;
414 hashtable_t
*entries
;
416 /** associated backtrace */
417 backtrace_t
*backtrace
;
418 /** total size of all allocations */
420 /** number of allocations */
425 before
= enable_thread(FALSE
);
427 entries
= hashtable_create((hashtable_hash_t
)hash
,
428 (hashtable_equals_t
)equals
, 1024);
430 for (hdr
= first_header
.next
; hdr
!= NULL
; hdr
= hdr
->next
)
433 hdr
->backtrace
->contains_function(hdr
->backtrace
,
434 whitelist
, countof(whitelist
)))
439 entry
= entries
->get(entries
, hdr
->backtrace
);
442 entry
->bytes
+= hdr
->bytes
;
448 .backtrace
= hdr
->backtrace
,
452 entries
->put(entries
, hdr
->backtrace
, entry
);
457 enumerator
= entries
->create_enumerator(entries
);
458 while (enumerator
->enumerate(enumerator
, NULL
, &entry
))
460 if (!thresh
|| entry
->bytes
>= thresh
)
462 fprintf(out
, "%d bytes total, %d allocations, %d bytes average:\n",
463 entry
->bytes
, entry
->count
, entry
->bytes
/ entry
->count
);
464 entry
->backtrace
->log(entry
->backtrace
, out
, detailed
);
468 enumerator
->destroy(enumerator
);
469 entries
->destroy(entries
);
471 enable_thread(before
);
475 METHOD(leak_detective_t
, report
, void,
476 private_leak_detective_t
*this, bool detailed
)
478 if (lib
->leak_detective
)
480 int leaks
= 0, whitelisted
= 0;
482 leaks
= print_traces(this, stderr
, 0, detailed
, &whitelisted
);
486 fprintf(stderr
, "No leaks detected");
489 fprintf(stderr
, "One leak detected");
492 fprintf(stderr
, "%d leaks detected", leaks
);
495 fprintf(stderr
, ", %d suppressed by whitelist\n", whitelisted
);
499 fprintf(stderr
, "Leak detective disabled\n");
503 METHOD(leak_detective_t
, set_state
, bool,
504 private_leak_detective_t
*this, bool enable
)
506 if (enable
== enabled
)
512 enable_leak_detective();
516 disable_leak_detective();
521 METHOD(leak_detective_t
, usage
, void,
522 private_leak_detective_t
*this, FILE *out
)
527 thresh
= lib
->settings
->get_int(lib
->settings
,
528 "libstrongswan.leak_detective.usage_threshold", 10240);
529 detailed
= lib
->settings
->get_bool(lib
->settings
,
530 "libstrongswan.leak_detective.detailed", TRUE
);
532 print_traces(this, out
, thresh
, detailed
, NULL
);
536 * Wrapped malloc() function
538 void* malloc(size_t bytes
)
540 memory_header_t
*hdr
;
544 if (!enabled
|| thread_disabled
->get(thread_disabled
))
546 return real_malloc(bytes
);
550 hdr
= real_malloc(sizeof(memory_header_t
) + bytes
+ sizeof(memory_tail_t
));
551 tail
= ((void*)hdr
) + bytes
+ sizeof(memory_header_t
);
552 /* set to something which causes crashes */
553 memset(hdr
, MEMORY_ALLOC_PATTERN
,
554 sizeof(memory_header_t
) + bytes
+ sizeof(memory_tail_t
));
556 before
= enable_thread(FALSE
);
557 hdr
->backtrace
= backtrace_create(2);
558 enable_thread(before
);
560 hdr
->magic
= MEMORY_HEADER_MAGIC
;
562 tail
->magic
= MEMORY_TAIL_MAGIC
;
564 /* insert at the beginning of the list */
566 hdr
->next
= first_header
.next
;
569 hdr
->next
->previous
= hdr
;
571 hdr
->previous
= &first_header
;
572 first_header
.next
= hdr
;
579 * Wrapped calloc() function
581 void* calloc(size_t nmemb
, size_t size
)
587 memset(ptr
, 0, size
);
593 * Wrapped free() function
597 memory_header_t
*hdr
, *current
;
599 backtrace_t
*backtrace
;
600 bool found
= FALSE
, before
;
602 if (!enabled
|| thread_disabled
->get(thread_disabled
))
607 /* allow freeing of NULL */
612 hdr
= ptr
- sizeof(memory_header_t
);
613 tail
= ptr
+ hdr
->bytes
;
616 before
= enable_thread(FALSE
);
617 if (hdr
->magic
!= MEMORY_HEADER_MAGIC
||
618 tail
->magic
!= MEMORY_TAIL_MAGIC
)
621 for (current
= &first_header
; current
!= NULL
; current
= current
->next
)
632 /* memory was allocated by our hooks but is corrupted */
633 fprintf(stderr
, "freeing corrupted memory (%p): "
634 "header magic 0x%x, tail magic 0x%x:\n",
635 ptr
, hdr
->magic
, tail
->magic
);
639 /* memory was not allocated by our hooks */
640 fprintf(stderr
, "freeing invalid memory (%p)\n", ptr
);
642 backtrace
= backtrace_create(2);
643 backtrace
->log(backtrace
, stderr
, TRUE
);
644 backtrace
->destroy(backtrace
);
648 /* remove item from list */
652 hdr
->next
->previous
= hdr
->previous
;
654 hdr
->previous
->next
= hdr
->next
;
657 hdr
->backtrace
->destroy(hdr
->backtrace
);
659 /* clear MAGIC, set mem to something remarkable */
660 memset(hdr
, MEMORY_FREE_PATTERN
,
661 sizeof(memory_header_t
) + hdr
->bytes
+ sizeof(memory_tail_t
));
665 enable_thread(before
);
669 * Wrapped realloc() function
671 void* realloc(void *old
, size_t bytes
)
673 memory_header_t
*hdr
;
675 backtrace_t
*backtrace
;
678 if (!enabled
|| thread_disabled
->get(thread_disabled
))
680 return real_realloc(old
, bytes
);
682 /* allow reallocation of NULL */
685 return malloc(bytes
);
688 hdr
= old
- sizeof(memory_header_t
);
689 tail
= old
+ hdr
->bytes
;
692 if (hdr
->magic
!= MEMORY_HEADER_MAGIC
||
693 tail
->magic
!= MEMORY_TAIL_MAGIC
)
695 fprintf(stderr
, "reallocating invalid memory (%p):\n"
696 "header magic 0x%x:\n", old
, hdr
->magic
);
697 backtrace
= backtrace_create(2);
698 backtrace
->log(backtrace
, stderr
, TRUE
);
699 backtrace
->destroy(backtrace
);
703 /* clear tail magic, allocate, set tail magic */
704 memset(&tail
->magic
, MEMORY_ALLOC_PATTERN
, sizeof(tail
->magic
));
706 hdr
= real_realloc(hdr
,
707 sizeof(memory_header_t
) + bytes
+ sizeof(memory_tail_t
));
708 tail
= ((void*)hdr
) + bytes
+ sizeof(memory_header_t
);
709 tail
->magic
= MEMORY_TAIL_MAGIC
;
711 /* update statistics */
714 before
= enable_thread(FALSE
);
715 hdr
->backtrace
->destroy(hdr
->backtrace
);
716 hdr
->backtrace
= backtrace_create(2);
717 enable_thread(before
);
719 /* update header of linked list neighbours */
723 hdr
->next
->previous
= hdr
;
725 hdr
->previous
->next
= hdr
;
731 METHOD(leak_detective_t
, destroy
, void,
732 private_leak_detective_t
*this)
734 disable_leak_detective();
736 thread_disabled
->destroy(thread_disabled
);
743 leak_detective_t
*leak_detective_create()
745 private_leak_detective_t
*this;
751 .set_state
= _set_state
,
756 lock
= spinlock_create();
757 thread_disabled
= thread_value_create(NULL
);
759 init_static_allocations();
761 if (getenv("LEAK_DETECTIVE_DISABLE") == NULL
)
763 enable_leak_detective();
765 return &this->public;