leak-detective: align allocations on both 32 and 64-bit systems to 32 bytes
[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
32 #include "leak_detective.h"
33
34 #include <library.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>
40
41 typedef struct private_leak_detective_t private_leak_detective_t;
42
43 /**
44 * private data of leak_detective
45 */
46 struct private_leak_detective_t {
47
48 /**
49 * public functions
50 */
51 leak_detective_t public;
52 };
53
54 /**
55 * Magic value which helps to detect memory corruption. Yummy!
56 */
57 #define MEMORY_HEADER_MAGIC 0x7ac0be11
58
59 /**
60 * Magic written to tail of allocation
61 */
62 #define MEMORY_TAIL_MAGIC 0xcafebabe
63
64 /**
65 * Pattern which is filled in memory before freeing it
66 */
67 #define MEMORY_FREE_PATTERN 0xFF
68
69 /**
70 * Pattern which is filled in newly allocated memory
71 */
72 #define MEMORY_ALLOC_PATTERN 0xEE
73
74 static u_int count_malloc = 0;
75 static u_int count_free = 0;
76 static u_int count_realloc = 0;
77
78 typedef struct memory_header_t memory_header_t;
79 typedef struct memory_tail_t memory_tail_t;
80
81 /**
82 * Header which is prepended to each allocated memory block
83 */
84 struct memory_header_t {
85
86 /**
87 * Pointer to previous entry in linked list
88 */
89 memory_header_t *previous;
90
91 /**
92 * Pointer to next entry in linked list
93 */
94 memory_header_t *next;
95
96 /**
97 * backtrace taken during (re-)allocation
98 */
99 backtrace_t *backtrace;
100
101 /**
102 * Padding to make sizeof(memory_header_t) == 32
103 */
104 u_int32_t padding[sizeof(void*) == sizeof(u_int32_t) ? 3 : 0];
105
106 /**
107 * Number of bytes following after the header
108 */
109 u_int32_t bytes;
110
111 /**
112 * magic bytes to detect bad free or heap underflow, MEMORY_HEADER_MAGIC
113 */
114 u_int32_t magic;
115
116 }__attribute__((__packed__));
117
118 /**
119 * tail appended to each allocated memory block
120 */
121 struct memory_tail_t {
122
123 /**
124 * Magic bytes to detect heap overflow, MEMORY_TAIL_MAGIC
125 */
126 u_int32_t magic;
127
128 }__attribute__((__packed__));
129
130 /**
131 * first mem header is just a dummy to chain
132 * the others on it...
133 */
134 static memory_header_t first_header = {
135 .magic = MEMORY_HEADER_MAGIC,
136 };
137
138 /**
139 * Spinlock to access header linked list
140 */
141 static spinlock_t *lock;
142
143 /**
144 * Is leak detection currently enabled?
145 */
146 static bool enabled = FALSE;
147
148 /**
149 * Is leak detection disabled for the current thread?
150 */
151 static thread_value_t *thread_disabled;
152
153 /**
154 * Installs the malloc hooks, enables leak detection
155 */
156 static void enable_leak_detective()
157 {
158 enabled = TRUE;
159 }
160
161 /**
162 * Uninstalls the malloc hooks, disables leak detection
163 */
164 static void disable_leak_detective()
165 {
166 enabled = FALSE;
167 }
168
169 /**
170 * Enable/Disable leak detective for the current thread
171 *
172 * @return Previous value
173 */
174 static bool enable_thread(bool enable)
175 {
176 bool before;
177
178 before = thread_disabled->get(thread_disabled) == NULL;
179 thread_disabled->set(thread_disabled, enable ? NULL : (void*)TRUE);
180 return before;
181 }
182
183 /**
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.
186 */
187 static void* malloc_for_dlsym(size_t size)
188 {
189 static char buf[1024] = {};
190 static size_t used = 0;
191 char *ptr;
192
193 /* roundup to a multiple of 32 */
194 size = (size - 1) / 32 * 32 + 32;
195
196 if (used + size > sizeof(buf))
197 {
198 return NULL;
199 }
200 ptr = buf + used;
201 used += size;
202 return ptr;
203 }
204
205 /**
206 * Lookup a malloc function, while disabling wrappers
207 */
208 static void* get_malloc_fn(char *name)
209 {
210 bool before = FALSE;
211 void *fn;
212
213 if (enabled)
214 {
215 before = enable_thread(FALSE);
216 }
217 fn = dlsym(RTLD_NEXT, name);
218 if (enabled)
219 {
220 enable_thread(before);
221 }
222 return fn;
223 }
224
225 /**
226 * Call original malloc()
227 */
228 static void* real_malloc(size_t size)
229 {
230 static void* (*fn)(size_t size);
231 static int recursive = 0;
232
233 if (!fn)
234 {
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. */
238 if (recursive)
239 {
240 return malloc_for_dlsym(size);
241 }
242 recursive++;
243 fn = get_malloc_fn("malloc");
244 recursive--;
245 }
246 return fn(size);
247 }
248
249 /**
250 * Call original free()
251 */
252 static void real_free(void *ptr)
253 {
254 static void (*fn)(void *ptr);
255
256 if (!fn)
257 {
258 fn = get_malloc_fn("free");
259 }
260 return fn(ptr);
261 }
262
263 /**
264 * Call original realloc()
265 */
266 static void* real_realloc(void *ptr, size_t size)
267 {
268 static void* (*fn)(void *ptr, size_t size);
269
270 if (!fn)
271 {
272 fn = get_malloc_fn("realloc");
273 }
274 return fn(ptr, size);
275 }
276
277 /**
278 * Leak report white list
279 *
280 * List of functions using static allocation buffers or should be suppressed
281 * otherwise on leak report.
282 */
283 char *whitelist[] = {
284 /* backtraces, including own */
285 "backtrace_create",
286 "safe_strerror",
287 /* pthread stuff */
288 "pthread_create",
289 "pthread_setspecific",
290 "__pthread_setspecific",
291 /* glibc functions */
292 "inet_ntoa",
293 "strerror",
294 "getprotobyname",
295 "getprotobynumber",
296 "getservbyport",
297 "getservbyname",
298 "gethostbyname",
299 "gethostbyname2",
300 "gethostbyname_r",
301 "gethostbyname2_r",
302 "getnetbyname",
303 "getpwnam_r",
304 "getgrnam_r",
305 "register_printf_function",
306 "register_printf_specifier",
307 "syslog",
308 "vsyslog",
309 "__syslog_chk",
310 "__vsyslog_chk",
311 "getaddrinfo",
312 "setlocale",
313 "getpass",
314 "getpwent_r",
315 "setpwent",
316 "endpwent",
317 "getspnam_r",
318 "getpwuid_r",
319 "initgroups",
320 /* ignore dlopen, as we do not dlclose to get proper leak reports */
321 "dlopen",
322 "dlerror",
323 "dlclose",
324 "dlsym",
325 /* mysql functions */
326 "mysql_init_character_set",
327 "init_client_errs",
328 "my_thread_init",
329 /* fastcgi library */
330 "FCGX_Init",
331 /* libxml */
332 "xmlInitCharEncodingHandlers",
333 "xmlInitParser",
334 "xmlInitParserCtxt",
335 /* libcurl */
336 "Curl_client_write",
337 /* ClearSilver */
338 "nerr_init",
339 /* OpenSSL */
340 "RSA_new_method",
341 "DH_new_method",
342 "ENGINE_load_builtin_engines",
343 "OPENSSL_config",
344 "ecdsa_check",
345 "ERR_put_error",
346 /* libgcrypt */
347 "gcry_control",
348 "gcry_check_version",
349 "gcry_randomize",
350 "gcry_create_nonce",
351 /* NSPR */
352 "PR_CallOnce",
353 /* libapr */
354 "apr_pool_create_ex",
355 /* glib */
356 "g_type_init_with_debug_flags",
357 "g_type_register_static",
358 "g_type_class_ref",
359 "g_type_create_instance",
360 "g_type_add_interface_static",
361 "g_type_interface_add_prerequisite",
362 "g_socket_connection_factory_lookup_type",
363 /* libgpg */
364 "gpg_err_init",
365 /* gnutls */
366 "gnutls_global_init",
367 };
368
369 /**
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
372 */
373 static void init_static_allocations()
374 {
375 tzset();
376 }
377
378 /**
379 * Hashtable hash function
380 */
381 static u_int hash(backtrace_t *key)
382 {
383 enumerator_t *enumerator;
384 void *addr;
385 u_int hash = 0;
386
387 enumerator = key->create_frame_enumerator(key);
388 while (enumerator->enumerate(enumerator, &addr))
389 {
390 hash = chunk_hash_inc(chunk_from_thing(addr), hash);
391 }
392 enumerator->destroy(enumerator);
393
394 return hash;
395 }
396
397 /**
398 * Hashtable equals function
399 */
400 static bool equals(backtrace_t *a, backtrace_t *b)
401 {
402 return a->equals(a, b);
403 }
404
405 /**
406 * Summarize and print backtraces
407 */
408 static int print_traces(private_leak_detective_t *this,
409 FILE *out, int thresh, bool detailed, int *whitelisted)
410 {
411 int leaks = 0;
412 memory_header_t *hdr;
413 enumerator_t *enumerator;
414 hashtable_t *entries;
415 struct {
416 /** associated backtrace */
417 backtrace_t *backtrace;
418 /** total size of all allocations */
419 size_t bytes;
420 /** number of allocations */
421 u_int count;
422 } *entry;
423 bool before;
424
425 before = enable_thread(FALSE);
426
427 entries = hashtable_create((hashtable_hash_t)hash,
428 (hashtable_equals_t)equals, 1024);
429 lock->lock(lock);
430 for (hdr = first_header.next; hdr != NULL; hdr = hdr->next)
431 {
432 if (whitelisted &&
433 hdr->backtrace->contains_function(hdr->backtrace,
434 whitelist, countof(whitelist)))
435 {
436 (*whitelisted)++;
437 continue;
438 }
439 entry = entries->get(entries, hdr->backtrace);
440 if (entry)
441 {
442 entry->bytes += hdr->bytes;
443 entry->count++;
444 }
445 else
446 {
447 INIT(entry,
448 .backtrace = hdr->backtrace,
449 .bytes = hdr->bytes,
450 .count = 1,
451 );
452 entries->put(entries, hdr->backtrace, entry);
453 }
454 leaks++;
455 }
456 lock->unlock(lock);
457 enumerator = entries->create_enumerator(entries);
458 while (enumerator->enumerate(enumerator, NULL, &entry))
459 {
460 if (!thresh || entry->bytes >= thresh)
461 {
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);
465 }
466 free(entry);
467 }
468 enumerator->destroy(enumerator);
469 entries->destroy(entries);
470
471 enable_thread(before);
472 return leaks;
473 }
474
475 METHOD(leak_detective_t, report, void,
476 private_leak_detective_t *this, bool detailed)
477 {
478 if (lib->leak_detective)
479 {
480 int leaks = 0, whitelisted = 0;
481
482 leaks = print_traces(this, stderr, 0, detailed, &whitelisted);
483 switch (leaks)
484 {
485 case 0:
486 fprintf(stderr, "No leaks detected");
487 break;
488 case 1:
489 fprintf(stderr, "One leak detected");
490 break;
491 default:
492 fprintf(stderr, "%d leaks detected", leaks);
493 break;
494 }
495 fprintf(stderr, ", %d suppressed by whitelist\n", whitelisted);
496 }
497 else
498 {
499 fprintf(stderr, "Leak detective disabled\n");
500 }
501 }
502
503 METHOD(leak_detective_t, set_state, bool,
504 private_leak_detective_t *this, bool enable)
505 {
506 if (enable == enabled)
507 {
508 return enabled;
509 }
510 if (enable)
511 {
512 enable_leak_detective();
513 }
514 else
515 {
516 disable_leak_detective();
517 }
518 return !enabled;
519 }
520
521 METHOD(leak_detective_t, usage, void,
522 private_leak_detective_t *this, FILE *out)
523 {
524 bool detailed;
525 int thresh;
526
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);
531
532 print_traces(this, out, thresh, detailed, NULL);
533 }
534
535 /**
536 * Wrapped malloc() function
537 */
538 void* malloc(size_t bytes)
539 {
540 memory_header_t *hdr;
541 memory_tail_t *tail;
542 bool before;
543
544 if (!enabled || thread_disabled->get(thread_disabled))
545 {
546 return real_malloc(bytes);
547 }
548
549 count_malloc++;
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));
555
556 before = enable_thread(FALSE);
557 hdr->backtrace = backtrace_create(2);
558 enable_thread(before);
559
560 hdr->magic = MEMORY_HEADER_MAGIC;
561 hdr->bytes = bytes;
562 tail->magic = MEMORY_TAIL_MAGIC;
563
564 /* insert at the beginning of the list */
565 lock->lock(lock);
566 hdr->next = first_header.next;
567 if (hdr->next)
568 {
569 hdr->next->previous = hdr;
570 }
571 hdr->previous = &first_header;
572 first_header.next = hdr;
573 lock->unlock(lock);
574
575 return hdr + 1;
576 }
577
578 /**
579 * Wrapped calloc() function
580 */
581 void* calloc(size_t nmemb, size_t size)
582 {
583 void *ptr;
584
585 size *= nmemb;
586 ptr = malloc(size);
587 memset(ptr, 0, size);
588
589 return ptr;
590 }
591
592 /**
593 * Wrapped free() function
594 */
595 void free(void *ptr)
596 {
597 memory_header_t *hdr, *current;
598 memory_tail_t *tail;
599 backtrace_t *backtrace;
600 bool found = FALSE, before;
601
602 if (!enabled || thread_disabled->get(thread_disabled))
603 {
604 real_free(ptr);
605 return;
606 }
607 /* allow freeing of NULL */
608 if (ptr == NULL)
609 {
610 return;
611 }
612 hdr = ptr - sizeof(memory_header_t);
613 tail = ptr + hdr->bytes;
614
615 count_free++;
616 before = enable_thread(FALSE);
617 if (hdr->magic != MEMORY_HEADER_MAGIC ||
618 tail->magic != MEMORY_TAIL_MAGIC)
619 {
620 lock->lock(lock);
621 for (current = &first_header; current != NULL; current = current->next)
622 {
623 if (current == hdr)
624 {
625 found = TRUE;
626 break;
627 }
628 }
629 lock->unlock(lock);
630 if (found)
631 {
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);
636 }
637 else
638 {
639 /* memory was not allocated by our hooks */
640 fprintf(stderr, "freeing invalid memory (%p)\n", ptr);
641 }
642 backtrace = backtrace_create(2);
643 backtrace->log(backtrace, stderr, TRUE);
644 backtrace->destroy(backtrace);
645 }
646 else
647 {
648 /* remove item from list */
649 lock->lock(lock);
650 if (hdr->next)
651 {
652 hdr->next->previous = hdr->previous;
653 }
654 hdr->previous->next = hdr->next;
655 lock->unlock(lock);
656
657 hdr->backtrace->destroy(hdr->backtrace);
658
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));
662
663 real_free(hdr);
664 }
665 enable_thread(before);
666 }
667
668 /**
669 * Wrapped realloc() function
670 */
671 void* realloc(void *old, size_t bytes)
672 {
673 memory_header_t *hdr;
674 memory_tail_t *tail;
675 backtrace_t *backtrace;
676 bool before;
677
678 if (!enabled || thread_disabled->get(thread_disabled))
679 {
680 return real_realloc(old, bytes);
681 }
682 /* allow reallocation of NULL */
683 if (old == NULL)
684 {
685 return malloc(bytes);
686 }
687
688 hdr = old - sizeof(memory_header_t);
689 tail = old + hdr->bytes;
690
691 count_realloc++;
692 if (hdr->magic != MEMORY_HEADER_MAGIC ||
693 tail->magic != MEMORY_TAIL_MAGIC)
694 {
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);
700 }
701 else
702 {
703 /* clear tail magic, allocate, set tail magic */
704 memset(&tail->magic, MEMORY_ALLOC_PATTERN, sizeof(tail->magic));
705 }
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;
710
711 /* update statistics */
712 hdr->bytes = bytes;
713
714 before = enable_thread(FALSE);
715 hdr->backtrace->destroy(hdr->backtrace);
716 hdr->backtrace = backtrace_create(2);
717 enable_thread(before);
718
719 /* update header of linked list neighbours */
720 lock->lock(lock);
721 if (hdr->next)
722 {
723 hdr->next->previous = hdr;
724 }
725 hdr->previous->next = hdr;
726 lock->unlock(lock);
727
728 return hdr + 1;
729 }
730
731 METHOD(leak_detective_t, destroy, void,
732 private_leak_detective_t *this)
733 {
734 disable_leak_detective();
735 lock->destroy(lock);
736 thread_disabled->destroy(thread_disabled);
737 free(this);
738 }
739
740 /*
741 * see header file
742 */
743 leak_detective_t *leak_detective_create()
744 {
745 private_leak_detective_t *this;
746
747 INIT(this,
748 .public = {
749 .report = _report,
750 .usage = _usage,
751 .set_state = _set_state,
752 .destroy = _destroy,
753 },
754 );
755
756 lock = spinlock_create();
757 thread_disabled = thread_value_create(NULL);
758
759 init_static_allocations();
760
761 if (getenv("LEAK_DETECTIVE_DISABLE") == NULL)
762 {
763 enable_leak_detective();
764 }
765 return &this->public;
766 }