]> git.ipfire.org Git - thirdparty/strongswan.git/blame - src/libstrongswan/utils/leak_detective.c
added skeleton for libgcrypt based crypto plugin
[thirdparty/strongswan.git] / src / libstrongswan / utils / leak_detective.c
CommitLineData
5113680f 1/*
552cc11b 2 * Copyright (C) 2006-2008 Martin Willi
5113680f
MW
3 * Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
552cc11b 15
7a485e90
MW
16#define _GNU_SOURCE
17#include <sched.h>
5113680f 18#include <stddef.h>
5113680f
MW
19#include <string.h>
20#include <stdio.h>
21#include <malloc.h>
5113680f
MW
22#include <signal.h>
23#include <sys/socket.h>
24#include <netinet/in.h>
25#include <arpa/inet.h>
1d025fbc 26#include <unistd.h>
8bc96e08 27#include <syslog.h>
8bc96e08 28#include <pthread.h>
b1904247 29#include <netdb.h>
552cc11b 30#include <locale.h>
5113680f
MW
31
32#include "leak_detective.h"
33
60356f33 34#include <library.h>
db7ef624 35#include <debug.h>
f7237cf3 36#include <utils/backtrace.h>
5113680f 37
552cc11b
MW
38typedef struct private_leak_detective_t private_leak_detective_t;
39
40/**
41 * private data of leak_detective
42 */
43struct private_leak_detective_t {
44
45 /**
46 * public functions
47 */
48 leak_detective_t public;
49};
5113680f
MW
50
51/**
269f7f44 52 * Magic value which helps to detect memory corruption. Yummy!
5113680f 53 */
269f7f44
MW
54#define MEMORY_HEADER_MAGIC 0x7ac0be11
55
b7ef3f62
MW
56/**
57 * Magic written to tail of allocation
58 */
59#define MEMORY_TAIL_MAGIC 0xcafebabe
60
269f7f44
MW
61/**
62 * Pattern which is filled in memory before freeing it
63 */
64#define MEMORY_FREE_PATTERN 0xFF
65
66/**
67 * Pattern which is filled in newly allocated memory
68 */
69#define MEMORY_ALLOC_PATTERN 0xEE
70
5113680f 71
5113680f
MW
72static void install_hooks(void);
73static void uninstall_hooks(void);
74static void *malloc_hook(size_t, const void *);
75static void *realloc_hook(void *, size_t, const void *);
76static void free_hook(void*, const void *);
73760ca5 77
cce97b64
MW
78void *(*old_malloc_hook)(size_t, const void *);
79void *(*old_realloc_hook)(void *, size_t, const void *);
80void (*old_free_hook)(void*, const void *);
81
73760ca5
MW
82static u_int count_malloc = 0;
83static u_int count_free = 0;
84static u_int count_realloc = 0;
5113680f
MW
85
86typedef struct memory_header_t memory_header_t;
b7ef3f62 87typedef struct memory_tail_t memory_tail_t;
5113680f
MW
88
89/**
90 * Header which is prepended to each allocated memory block
91 */
92struct memory_header_t {
5113680f
MW
93
94 /**
95 * Number of bytes following after the header
96 */
b7ef3f62 97 u_int bytes;
5113680f 98
5113680f
MW
99 /**
100 * Pointer to previous entry in linked list
101 */
102 memory_header_t *previous;
103
104 /**
105 * Pointer to next entry in linked list
106 */
107 memory_header_t *next;
b7ef3f62 108
f7237cf3
MW
109 /**
110 * backtrace taken during (re-)allocation
111 */
112 backtrace_t *backtrace;
113
b7ef3f62
MW
114 /**
115 * magic bytes to detect bad free or heap underflow, MEMORY_HEADER_MAGIC
116 */
117 u_int32_t magic;
118
119}__attribute__((__packed__));
120
121/**
122 * tail appended to each allocated memory block
123 */
124struct memory_tail_t {
125
126 /**
127 * Magic bytes to detect heap overflow, MEMORY_TAIL_MAGIC
128 */
129 u_int32_t magic;
130
131}__attribute__((__packed__));
5113680f
MW
132
133/**
134 * first mem header is just a dummy to chain
135 * the others on it...
136 */
6b3292da 137static memory_header_t first_header = {
5113680f
MW
138 magic: MEMORY_HEADER_MAGIC,
139 bytes: 0,
f7237cf3 140 backtrace: NULL,
5113680f
MW
141 previous: NULL,
142 next: NULL
143};
144
1d025fbc 145/**
6b3292da 146 * are the hooks currently installed?
1d025fbc 147 */
6b3292da 148static bool installed = FALSE;
5113680f 149
986d23bd 150/**
552cc11b 151 * Leak report white list
151168f6 152 *
552cc11b
MW
153 * List of functions using static allocation buffers or should be suppressed
154 * otherwise on leak report.
986d23bd 155 */
552cc11b 156char *whitelist[] = {
f7237cf3
MW
157 /* backtraces, including own */
158 "backtrace_create",
7939864d 159 /* pthread stuff */
552cc11b
MW
160 "pthread_create",
161 "pthread_setspecific",
9eb85cff 162 "__pthread_setspecific",
7939864d 163 /* glibc functions */
552cc11b 164 "mktime",
e69f33f6 165 "__gmtime_r",
c198fc55 166 "localtime_r",
552cc11b
MW
167 "tzset",
168 "inet_ntoa",
169 "strerror",
170 "getprotobynumber",
171 "getservbyport",
172 "getservbyname",
5a22a021
MW
173 "gethostbyname_r",
174 "gethostbyname2_r",
25b12c69
MW
175 "getpwnam_r",
176 "getgrnam_r",
552cc11b
MW
177 "register_printf_function",
178 "syslog",
179 "vsyslog",
552cc11b
MW
180 "getaddrinfo",
181 "setlocale",
7939864d
MW
182 /* ignore dlopen, as we do not dlclose to get proper leak reports */
183 "dlopen",
a3d92a37 184 "dlerror",
1caa265c 185 "dlclose",
7939864d 186 /* mysql functions */
552cc11b
MW
187 "mysql_init_character_set",
188 "init_client_errs",
189 "my_thread_init",
7939864d 190 /* fastcgi library */
cf4caefa 191 "FCGX_Init",
7939864d
MW
192 /* libxml */
193 "xmlInitCharEncodingHandlers",
194 "xmlInitParser",
195 "xmlInitParserCtxt",
196 /* ClearSilver */
197 "nerr_init",
915e04b2
MW
198 /* OpenSSL */
199 "RSA_new_method",
200 "DH_new_method",
fe5d7c43 201 "ENGINE_load_builtin_engines",
04425625 202 "OPENSSL_config",
986d23bd
MW
203};
204
205/**
552cc11b 206 * check if a stack frame contains functions listed above
986d23bd 207 */
f7237cf3 208static bool is_whitelisted(backtrace_t *backtrace)
986d23bd 209{
f7237cf3
MW
210 int i;
211 for (i = 0; i < sizeof(whitelist)/sizeof(char*); i++)
986d23bd 212 {
f7237cf3
MW
213 if (backtrace->contains_function(backtrace, whitelist[i]))
214 {
215 return TRUE;
986d23bd
MW
216 }
217 }
218 return FALSE;
219}
220
6b3292da
MW
221/**
222 * Report leaks at library destruction
223 */
224void report_leaks()
225{
226 memory_header_t *hdr;
cf4caefa 227 int leaks = 0, whitelisted = 0;
6b3292da 228
6b3292da
MW
229 for (hdr = first_header.next; hdr != NULL; hdr = hdr->next)
230 {
f7237cf3 231 if (is_whitelisted(hdr->backtrace))
cf4caefa
MW
232 {
233 whitelisted++;
234 }
235 else
986d23bd 236 {
552cc11b
MW
237 fprintf(stderr, "Leak (%d bytes at %p):\n", hdr->bytes, hdr + 1);
238 /* skip the first frame, contains leak detective logic */
f7237cf3 239 hdr->backtrace->log(hdr->backtrace, stderr);
986d23bd
MW
240 leaks++;
241 }
6b3292da
MW
242 }
243
244 switch (leaks)
245 {
246 case 0:
cf4caefa 247 fprintf(stderr, "No leaks detected");
6b3292da
MW
248 break;
249 case 1:
cf4caefa 250 fprintf(stderr, "One leak detected");
6b3292da
MW
251 break;
252 default:
cf4caefa 253 fprintf(stderr, "%d leaks detected", leaks);
6b3292da
MW
254 break;
255 }
cf4caefa 256 fprintf(stderr, ", %d suppressed by whitelist\n", whitelisted);
6b3292da
MW
257}
258
5113680f
MW
259/**
260 * Installs the malloc hooks, enables leak detection
261 */
6b3292da 262static void install_hooks()
5113680f 263{
8bc96e08
MW
264 if (!installed)
265 {
266 old_malloc_hook = __malloc_hook;
267 old_realloc_hook = __realloc_hook;
268 old_free_hook = __free_hook;
269 __malloc_hook = malloc_hook;
270 __realloc_hook = realloc_hook;
271 __free_hook = free_hook;
272 installed = TRUE;
273 }
5113680f
MW
274}
275
276/**
277 * Uninstalls the malloc hooks, disables leak detection
278 */
6b3292da 279static void uninstall_hooks()
5113680f 280{
8bc96e08
MW
281 if (installed)
282 {
283 __malloc_hook = old_malloc_hook;
284 __free_hook = old_free_hook;
285 __realloc_hook = old_realloc_hook;
286 installed = FALSE;
287 }
5113680f
MW
288}
289
290/**
291 * Hook function for malloc()
292 */
6b3292da 293void *malloc_hook(size_t bytes, const void *caller)
5113680f
MW
294{
295 memory_header_t *hdr;
b7ef3f62 296 memory_tail_t *tail;
84b18d5f
TB
297 pthread_t thread_id = pthread_self();
298 int oldpolicy;
299 struct sched_param oldparams, params;
300
301 pthread_getschedparam(thread_id, &oldpolicy, &oldparams);
302
303 params.__sched_priority = sched_get_priority_max(SCHED_FIFO);
304 pthread_setschedparam(thread_id, SCHED_FIFO, &params);
5113680f 305
73760ca5 306 count_malloc++;
5113680f 307 uninstall_hooks();
b7ef3f62
MW
308 hdr = malloc(sizeof(memory_header_t) + bytes + sizeof(memory_tail_t));
309 tail = ((void*)hdr) + bytes + sizeof(memory_header_t);
986d23bd 310 /* set to something which causes crashes */
b7ef3f62
MW
311 memset(hdr, MEMORY_ALLOC_PATTERN,
312 sizeof(memory_header_t) + bytes + sizeof(memory_tail_t));
5113680f
MW
313
314 hdr->magic = MEMORY_HEADER_MAGIC;
315 hdr->bytes = bytes;
f7237cf3 316 hdr->backtrace = backtrace_create(3);
b7ef3f62 317 tail->magic = MEMORY_TAIL_MAGIC;
269f7f44 318 install_hooks();
5113680f
MW
319
320 /* insert at the beginning of the list */
321 hdr->next = first_header.next;
322 if (hdr->next)
323 {
324 hdr->next->previous = hdr;
325 }
326 hdr->previous = &first_header;
327 first_header.next = hdr;
84b18d5f
TB
328
329 pthread_setschedparam(thread_id, oldpolicy, &oldparams);
330
5113680f
MW
331 return hdr + 1;
332}
333
334/**
335 * Hook function for free()
336 */
6b3292da 337void free_hook(void *ptr, const void *caller)
5113680f 338{
b7ef3f62
MW
339 memory_header_t *hdr;
340 memory_tail_t *tail;
f7237cf3 341 backtrace_t *backtrace;
84b18d5f
TB
342 pthread_t thread_id = pthread_self();
343 int oldpolicy;
344 struct sched_param oldparams, params;
345
5113680f
MW
346 /* allow freeing of NULL */
347 if (ptr == NULL)
348 {
349 return;
350 }
b7ef3f62
MW
351 hdr = ptr - sizeof(memory_header_t);
352 tail = ptr + hdr->bytes;
5113680f 353
84b18d5f
TB
354 pthread_getschedparam(thread_id, &oldpolicy, &oldparams);
355
356 params.__sched_priority = sched_get_priority_max(SCHED_FIFO);
357 pthread_setschedparam(thread_id, SCHED_FIFO, &params);
358
73760ca5 359 count_free++;
269f7f44 360 uninstall_hooks();
6c45e622
MW
361 if (hdr->magic != MEMORY_HEADER_MAGIC ||
362 tail->magic != MEMORY_TAIL_MAGIC)
5113680f 363 {
6c45e622
MW
364 fprintf(stderr, "freeing invalid memory (%p): "
365 "header magic 0x%x, tail magic 0x%x:\n",
366 ptr, hdr->magic, tail->magic);
f7237cf3
MW
367 backtrace = backtrace_create(3);
368 backtrace->log(backtrace, stderr);
369 backtrace->destroy(backtrace);
5113680f 370 }
6c45e622 371 else
b7ef3f62 372 {
6c45e622
MW
373 /* remove item from list */
374 if (hdr->next)
375 {
376 hdr->next->previous = hdr->previous;
377 }
378 hdr->previous->next = hdr->next;
f7237cf3
MW
379 hdr->backtrace->destroy(hdr->backtrace);
380
6c45e622
MW
381 /* clear MAGIC, set mem to something remarkable */
382 memset(hdr, MEMORY_FREE_PATTERN, hdr->bytes + sizeof(memory_header_t));
f7237cf3 383
6c45e622
MW
384 free(hdr);
385 }
269f7f44 386
5113680f 387 install_hooks();
6c90949f 388 pthread_setschedparam(thread_id, oldpolicy, &oldparams);
5113680f
MW
389}
390
391/**
392 * Hook function for realloc()
393 */
6b3292da 394void *realloc_hook(void *old, size_t bytes, const void *caller)
5113680f 395{
a401efd0 396 memory_header_t *hdr;
b7ef3f62 397 memory_tail_t *tail;
f7237cf3 398 backtrace_t *backtrace;
84b18d5f
TB
399 pthread_t thread_id = pthread_self();
400 int oldpolicy;
401 struct sched_param oldparams, params;
402
5113680f
MW
403 /* allow reallocation of NULL */
404 if (old == NULL)
405 {
406 return malloc_hook(bytes, caller);
407 }
a401efd0
MW
408
409 hdr = old - sizeof(memory_header_t);
b7ef3f62 410 tail = old + hdr->bytes;
269f7f44 411
84b18d5f
TB
412 pthread_getschedparam(thread_id, &oldpolicy, &oldparams);
413
414 params.__sched_priority = sched_get_priority_max(SCHED_FIFO);
415 pthread_setschedparam(thread_id, SCHED_FIFO, &params);
416
73760ca5 417 count_realloc++;
a401efd0 418 uninstall_hooks();
6c45e622
MW
419 if (hdr->magic != MEMORY_HEADER_MAGIC ||
420 tail->magic != MEMORY_TAIL_MAGIC)
b7ef3f62 421 {
6c45e622
MW
422 fprintf(stderr, "reallocating invalid memory (%p): "
423 "header magic 0x%x, tail magic 0x%x:\n",
424 old, hdr->magic, tail->magic);
f7237cf3
MW
425 backtrace = backtrace_create(3);
426 backtrace->log(backtrace, stderr);
427 backtrace->destroy(backtrace);
b7ef3f62
MW
428 }
429 /* clear tail magic, allocate, set tail magic */
430 memset(&tail->magic, MEMORY_ALLOC_PATTERN, sizeof(tail->magic));
431 hdr = realloc(hdr, sizeof(memory_header_t) + bytes + sizeof(memory_tail_t));
432 tail = ((void*)hdr) + bytes + sizeof(memory_header_t);
433 tail->magic = MEMORY_TAIL_MAGIC;
6c45e622 434
a401efd0
MW
435 /* update statistics */
436 hdr->bytes = bytes;
f7237cf3
MW
437 hdr->backtrace->destroy(hdr->backtrace);
438 hdr->backtrace = backtrace_create(3);
6c45e622 439
a401efd0
MW
440 /* update header of linked list neighbours */
441 if (hdr->next)
442 {
443 hdr->next->previous = hdr;
444 }
445 hdr->previous->next = hdr;
446 install_hooks();
84b18d5f 447 pthread_setschedparam(thread_id, oldpolicy, &oldparams);
a401efd0 448 return hdr + 1;
5113680f
MW
449}
450
451/**
552cc11b 452 * Implementation of leak_detective_t.destroy
5113680f 453 */
552cc11b 454static void destroy(private_leak_detective_t *this)
5113680f 455{
552cc11b 456 if (installed)
9cc7a297
MW
457 {
458 uninstall_hooks();
459 report_leaks();
460 }
552cc11b 461 free(this);
6b3292da
MW
462}
463
552cc11b
MW
464/*
465 * see header file
73760ca5 466 */
552cc11b 467leak_detective_t *leak_detective_create()
73760ca5 468{
552cc11b 469 private_leak_detective_t *this = malloc_thing(private_leak_detective_t);
73760ca5 470
552cc11b 471 this->public.destroy = (void(*)(leak_detective_t*))destroy;
9cc7a297 472
552cc11b 473 if (getenv("LEAK_DETECTIVE_DISABLE") == NULL)
73760ca5 474 {
7a485e90
MW
475 cpu_set_t mask;
476
477 CPU_ZERO(&mask);
478 CPU_SET(0, &mask);
479
480 if (sched_setaffinity(0, sizeof(cpu_set_t), &mask) != 0)
481 {
482 fprintf(stderr, "setting CPU affinity failed: %m");
483 }
484
e609b1cd 485 lib->leak_detective = TRUE;
552cc11b 486 install_hooks();
73760ca5 487 }
552cc11b 488 return &this->public;
73760ca5
MW
489}
490