bug 1083: Fix infinite loop in decompress_data
[elinks.git] / src / util / memdebug.c
blob8551c52382d31aab38fcbdc301213b788f641961
1 /** Memory debugging (leaks, overflows & co)
2 * @file
4 * Wrappers for libc memory managment providing protection against common
5 * pointers manipulation mistakes - bad realloc()/free() pointers, double
6 * free() problem, using uninitialized/freed memory, underflow/overflow
7 * protection, leaks tracking...
9 * Copyright (C) 1999 - 2002 Mikulas Patocka
10 * Copyright (C) 2001 - 2004 Petr Baudis
11 * Copyright (C) 2002 - 2003 Laurent Monin
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 * This file is covered by the General Public Licence v2. */
28 /* This file is very useful even for projects other than ELinks and I like to
29 * refer to it through its cvsweb URL, therefore it is a good thing to include
30 * the full copyright header here, contrary to the usual ELinks customs. */
32 #ifdef HAVE_CONFIG_H
33 #include "config.h"
34 #endif
36 #include <signal.h>
37 #include <stdarg.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #ifdef HAVE_UNISTD_H
42 #include <unistd.h>
43 #endif
45 #include "elinks.h"
47 #include "util/error.h"
48 #include "util/lists.h"
49 #include "util/memdebug.h"
50 #include "util/memory.h"
51 #include "util/string.h"
54 #ifdef DEBUG_MEMLEAK
56 /** Eat less memory, but sacrifice speed?
57 * Default is defined. */
58 #define LESS_MEMORY_SPEED
60 /** Fill memory on alloc() ?
61 * Default is defined. */
62 #define FILL_ON_ALLOC
63 #define FILL_ON_ALLOC_VALUE 'X'
65 /** Fill memory on realloc() ?
66 * Default is defined. */
67 #define FILL_ON_REALLOC
68 #define FILL_ON_REALLOC_VALUE 'Y'
70 /** Fill memory before free() ?
71 * Default is undef. */
72 #undef FILL_ON_FREE
73 #define FILL_ON_FREE_VALUE 'Z'
75 /** Check alloc_header block sanity ?
76 * Default is defined. */
77 #define CHECK_AH_SANITY
78 #define AH_SANITY_MAGIC 0xD3BA110C
80 /** Check for useless reallocation ?
81 * If oldsize is equal to newsize, print a message to stderr.
82 * It may help to find inefficient code.
83 * Default is undefined.
85 #undef CHECK_USELESS_REALLOC
87 /** Check for validity of address passed to free() ?
88 * Note that this is VERY slow, as we iterate through whole memory_list each
89 * time. We can't check magics etc, as it would break double free() check.
90 * Default is undef. */
91 #undef CHECK_INVALID_FREE
93 /** Check for double free ?
94 * Default is defined. */
95 #define CHECK_DOUBLE_FREE
96 #define AH_FREE_MAGIC 0xD3BF110C
98 /** Check for overflows and underflows ?
99 * Default is defined. */
100 #define CHECK_XFLOWS
101 #define XFLOW_MAGIC (char) 0xFA
103 /* Log all (de-)allocations to stderr (huge and slow)
104 * Default is undefined. */
105 /* #define LOG_MEMORY_ALLOC */
107 /* --------- end of debugger configuration section */
110 struct alloc_header {
111 LIST_HEAD(struct alloc_header);
113 #ifdef CHECK_AH_SANITY
114 int magic;
115 #endif
116 int size;
117 int line;
118 const unsigned char *file;
119 unsigned char *comment;
121 #ifdef CHECK_XFLOWS
122 /** This is a little magic. We want to keep the main pointer aligned,
123 * that means we want to have the xflow underflow mark in the
124 * alloc_header space, but at the _end_ of the aligned reserved space.
125 * This means we in fact live at [SIZE_AH_ALIGNED - 1], not here. (Of
126 * course this might be equivalent in some cases, but it is very
127 * unlikely in practice.) */
128 unsigned char xflow_underflow_placeholder;
129 #endif
132 /* Size is set to be on boundary of 8 (a multiple of 7) in order to have the
133 * main ptr aligned properly (faster access). We hope that */
134 #ifdef LESS_MEMORY_SPEED
135 #define SIZE_AH_ALIGNED ((sizeof(struct alloc_header) + 7) & ~7)
136 #else
137 /* Especially on 128bit machines, this can be faster, but eats more memory. */
138 #define SIZE_AH_ALIGNED ((sizeof(struct alloc_header) + 15) & ~15)
139 #endif
141 #ifdef CHECK_XFLOWS
142 #define XFLOW_INC 1
143 #else
144 #define XFLOW_INC 0
145 #endif
147 /* These macros are used to convert pointers and sizes to or from real ones
148 * when using alloc_header stuff. */
149 #define PTR_AH2BASE(ah) (void *) ((char *) (ah) + SIZE_AH_ALIGNED)
150 #define PTR_BASE2AH(ptr) (struct alloc_header *) \
151 ((char *) (ptr) - SIZE_AH_ALIGNED)
153 /* The second overflow mark is not embraced in SIZE_AH_ALIGNED. */
154 #define SIZE_BASE2AH(size) ((size) + SIZE_AH_ALIGNED + XFLOW_INC)
155 #define SIZE_AH2BASE(size) ((size) - SIZE_AH_ALIGNED - XFLOW_INC)
157 #ifdef CHECK_XFLOWS
158 #define PTR_OVERFLOW_MAGIC(ah) ((char *) PTR_AH2BASE(ah) + (ah)->size)
159 #define PTR_UNDERFLOW_MAGIC(ah) ((char *) PTR_AH2BASE(ah) - 1)
160 #define SET_OVERFLOW_MAGIC(ah) (*PTR_OVERFLOW_MAGIC(ah) = XFLOW_MAGIC)
161 #define SET_UNDERFLOW_MAGIC(ah) (*PTR_UNDERFLOW_MAGIC(ah) = XFLOW_MAGIC)
162 #define SET_XFLOW_MAGIC(ah) SET_OVERFLOW_MAGIC(ah), SET_UNDERFLOW_MAGIC(ah)
163 #endif
165 struct mem_stats mem_stats;
167 INIT_LIST_OF(struct alloc_header, memory_list);
169 #ifdef LOG_MEMORY_ALLOC
170 static void
171 dump_short_info(struct alloc_header *ah, const unsigned char *file, int line,
172 const unsigned char *type)
174 fprintf(stderr, "%p", PTR_AH2BASE(ah)), fflush(stderr);
175 fprintf(stderr, ":%d", ah->size), fflush(stderr);
176 if (type && *type) fprintf(stderr, " %s", type), fflush(stderr);
177 fprintf(stderr, " @ %s:%d ", file, line), fflush(stderr);
178 if (strcmp(file, ah->file) || line != ah->line)
179 fprintf(stderr, "< %s:%d", ah->file, ah->line), fflush(stderr);
180 if (ah->comment) fprintf(stderr, " [%s]", ah->comment), fflush(stderr);
181 fprintf(stderr, "\n"), fflush(stderr);
183 #else
184 #define dump_short_info(a, b, c, d)
185 #endif
187 static void
188 dump_info(struct alloc_header *ah, const unsigned char *info,
189 const unsigned char *file, int line, const unsigned char *type)
191 fprintf(stderr, "%p", PTR_AH2BASE(ah)); fflush(stderr);
192 /* In some extreme cases, we may core here, as 'ah' can no longer point
193 * to valid memory area (esp. when used in debug_mem_free()). */
194 fprintf(stderr, ":%d", ah->size);
196 if (type && *type) fprintf(stderr, " \033[1m%s\033[0m", type);
198 if (info && *info) fprintf(stderr, " %s", info);
200 fprintf(stderr, " @ ");
202 /* Following is commented out, as we want to print this out even when
203 * there're lions in ah, pointing us to evil places in memory, leading
204 * to segfaults and stuff like that. --pasky */
205 /* if (file && (strcmp(file, ah->file) || line != ah->line)) */
206 if (file) fprintf(stderr, "%s:%d, ", file, line), fflush(stderr);
208 fprintf(stderr, "alloc'd at %s:%d", ah->file, ah->line);
210 if (ah->comment) fprintf(stderr, " [%s]", ah->comment);
212 fprintf(stderr, "\n");
215 #ifdef CHECK_AH_SANITY
216 static inline int
217 bad_ah_sanity(struct alloc_header *ah, const unsigned char *info,
218 const unsigned char *file, int line)
220 if (!ah) return 1;
221 if (ah->magic != AH_SANITY_MAGIC) {
222 dump_info(ah, info, file, line, "bad alloc_header block");
223 return 1;
226 return 0;
228 #endif /* CHECK_AH_SANITY */
230 #ifdef CHECK_XFLOWS
231 static inline int
232 bad_xflow_magic(struct alloc_header *ah, const unsigned char *info,
233 const unsigned char *file, int line)
235 if (!ah) return 1;
237 if (*PTR_OVERFLOW_MAGIC(ah) != XFLOW_MAGIC) {
238 dump_info(ah, info, file, line, "overflow detected");
239 return 1;
242 if (*PTR_UNDERFLOW_MAGIC(ah) != XFLOW_MAGIC) {
243 dump_info(ah, info, file, line, "underflow detected");
244 return 1;
247 return 0;
249 #endif /* CHECK_XFLOWS */
252 void
253 check_memory_leaks(void)
255 struct alloc_header *ah;
257 if (!mem_stats.amount) {
258 /* No leaks - escape now. */
259 if (mem_stats.true_amount) /* debug memory leak ? */
260 fprintf(stderr, "\n\033[1mDebug memory leak by %ld bytes\033[0m\n",
261 mem_stats.true_amount);
263 return;
266 fprintf(stderr, "\n\033[1mMemory leak by %ld bytes\033[0m\n",
267 mem_stats.amount);
269 fprintf(stderr, "List of blocks:\n");
270 foreach (ah, memory_list) {
271 #ifdef CHECK_AH_SANITY
272 if (bad_ah_sanity(ah, "Skipped", NULL, 0)) continue;
273 #endif
274 #ifdef CHECK_XFLOWS
275 if (bad_xflow_magic(ah, NULL, NULL, 0)) continue;
276 #endif
277 dump_info(ah, NULL, NULL, 0, NULL);
280 force_dump();
283 static int alloc_try = 0;
285 static int
286 patience(const unsigned char *file, int line, const unsigned char *of)
288 errfile = file;
289 errline = line;
291 ++alloc_try;
292 if (alloc_try < ALLOC_MAXTRIES) {
293 elinks_error("Out of memory (%s returned NULL): retry #%d/%d, "
294 "I still exercise my patience and retry tirelessly.",
295 of, alloc_try, ALLOC_MAXTRIES);
296 sleep(ALLOC_DELAY);
297 return alloc_try;
300 #ifdef CRASH_IF_ALLOC_MAXTRIES
301 elinks_internal("Out of memory (%s returned NULL) after %d tries, "
302 "I give up. See ya on the other side.",
303 of, alloc_try);
304 #else
305 elinks_error("Out of memory (%s returned NULL) after %d tries, "
306 "I give up and try to continue. Pray for me, please.",
307 of, alloc_try);
308 #endif
309 alloc_try = 0;
310 return 0;
313 void *
314 debug_mem_alloc(const unsigned char *file, int line, size_t size)
316 struct alloc_header *ah;
317 size_t true_size;
319 if (!size) return NULL;
321 true_size = SIZE_BASE2AH(size);
322 do {
323 #ifdef CONFIG_GC
324 ah = GC_MALLOC(true_size);
325 #else
326 ah = malloc(true_size);
327 #endif
328 if (ah) break;
329 } while (patience(file, line, "malloc"));
330 if (!ah) return NULL;
332 #ifdef FILL_ON_ALLOC
333 memset(ah, FILL_ON_ALLOC_VALUE, SIZE_BASE2AH(size));
334 #endif
336 mem_stats.true_amount += true_size;
337 mem_stats.amount += size;
339 ah->size = size;
340 #ifdef CHECK_AH_SANITY
341 ah->magic = AH_SANITY_MAGIC;
342 #endif
343 ah->file = file;
344 ah->line = line;
345 ah->comment = NULL;
346 #ifdef CHECK_XFLOWS
347 SET_XFLOW_MAGIC(ah);
348 #endif
350 add_to_list(memory_list, ah);
352 dump_short_info(ah, file, line, "malloc");
354 return PTR_AH2BASE(ah);
357 void *
358 debug_mem_calloc(const unsigned char *file, int line, size_t eltcount, size_t eltsize)
360 struct alloc_header *ah;
361 size_t size = eltcount * eltsize;
362 size_t true_size;
364 if (!size) return NULL;
366 /* FIXME: Unfortunately, we can't pass eltsize through to calloc()
367 * itself, because we add bloat like alloc_header to it, which is
368 * difficult to be measured in eltsize. Maybe we should round it up to
369 * next eltsize multiple, but would it be worth the possibly wasted
370 * space? Someone should make some benchmarks. If you still read this
371 * comment, it means YOU should help us and do the benchmarks! :)
372 * Thanks a lot. --pasky */
374 true_size = SIZE_BASE2AH(size);
375 do {
376 #ifdef CONFIG_GC
377 ah = GC_MALLOC(true_size);
378 #else
379 ah = calloc(1, true_size);
380 #endif
381 if (ah) break;
382 } while (patience(file, line, "calloc"));
383 if (!ah) return NULL;
385 /* No, we do NOT want to fill this with FILL_ON_ALLOC_VALUE ;)). */
387 mem_stats.true_amount += true_size;
388 mem_stats.amount += size;
390 ah->size = size;
391 #ifdef CHECK_AH_SANITY
392 ah->magic = AH_SANITY_MAGIC;
393 #endif
394 ah->file = file;
395 ah->line = line;
396 ah->comment = NULL;
397 #ifdef CHECK_XFLOWS
398 SET_XFLOW_MAGIC(ah);
399 #endif
401 add_to_list(memory_list, ah);
403 dump_short_info(ah, file, line, "calloc");
405 return PTR_AH2BASE(ah);
408 void
409 debug_mem_free(const unsigned char *file, int line, void *ptr)
411 struct alloc_header *ah;
412 int ok = 1;
414 if (!ptr) {
415 errfile = file;
416 errline = line;
417 elinks_internal("mem_free(NULL)");
418 return;
421 #ifdef CHECK_INVALID_FREE
422 ok = 0;
423 foreach (ah, memory_list) {
424 if (ah == PTR_BASE2AH(ptr)) {
425 ok = 1;
426 break;
429 #endif
431 ah = PTR_BASE2AH(ptr);
433 if (!ok) {
434 /* This will get optimized out when not CHECK_INVALID_FREE. */
435 dump_info(ah, "free()", file, line, "invalid address");
436 return;
439 #ifdef CHECK_DOUBLE_FREE
440 if (ah->magic == AH_FREE_MAGIC) {
441 dump_info(ah, "free()", file, line, "double free");
442 /* If we already survived it chances are we could get over it.
443 * So let's not be overly tragic immediatelly. Just make sure
444 * the developer saw it. */
445 sleep(1);
447 #endif
449 #ifdef CHECK_AH_SANITY
450 if (bad_ah_sanity(ah, "free()", file, line))
451 force_dump();
452 #endif
453 #ifdef CHECK_XFLOWS
454 if (bad_xflow_magic(ah, "free()", file, line))
455 force_dump();
456 #endif
458 dump_short_info(ah, file, line, "free");
460 if (ah->comment) {
461 mem_stats.true_amount -= strlen(ah->comment) + 1;
462 #ifdef CONFIG_GC
463 ah->comment = NULL;
464 #else
465 free(ah->comment);
466 #endif
469 del_from_list(ah);
471 mem_stats.true_amount -= SIZE_BASE2AH(ah->size);
472 mem_stats.amount -= ah->size;
474 #ifdef FILL_ON_FREE
475 memset(ah, FILL_ON_FREE_VALUE, SIZE_BASE2AH(ah->size));
476 #endif
477 #ifdef CHECK_DOUBLE_FREE
478 ah->magic = AH_FREE_MAGIC;
479 #endif
481 #ifdef CONFIG_GC
482 ah = NULL;
483 #else
484 free(ah);
485 #endif
488 void *
489 debug_mem_realloc(const unsigned char *file, int line, void *ptr, size_t size)
491 struct alloc_header *ah, *ah2;
492 size_t true_size;
494 if (!ptr) return debug_mem_alloc(file, line, size);
496 /* Frees memory if size is zero. */
497 if (!size) {
498 debug_mem_free(file, line, ptr);
499 return NULL;
502 ah = PTR_BASE2AH(ptr);
504 #ifdef CHECK_AH_SANITY
505 if (bad_ah_sanity(ah, "realloc()", file, line)) force_dump();
506 #endif
507 #ifdef CHECK_XFLOWS
508 if (bad_xflow_magic(ah, "realloc()", file, line)) force_dump();
509 #endif
511 /* We compare oldsize to new size, and if equal we just return ptr
512 * and change nothing, this conforms to usual realloc() behavior. */
513 if (ah->size == size) {
514 #ifdef CHECK_USELESS_REALLOC
515 fprintf(stderr, "[%s:%d] mem_realloc() oldsize = newsize = %zu\n", file, line, size);
516 #endif
517 return (void *) ptr;
520 true_size = SIZE_BASE2AH(size);
521 do {
522 #ifdef CONFIG_GC
523 ah2 = GC_REALLOC(ah, true_size);
524 #else
525 ah2 = realloc(ah, true_size);
526 #endif
527 if (ah2) {
528 ah = ah2;
529 break;
531 } while (patience(file, line, "realloc"));
532 if (!ah2) return NULL;
534 mem_stats.true_amount += true_size - SIZE_BASE2AH(ah->size);
535 mem_stats.amount += size - ah->size;
537 #ifdef FILL_ON_REALLOC
538 if (size > ah->size)
539 memset((char *) PTR_AH2BASE(ah) + ah->size,
540 FILL_ON_REALLOC_VALUE, size - ah->size);
541 #endif
543 ah->size = size;
544 #ifdef CHECK_AH_SANITY
545 ah->magic = AH_SANITY_MAGIC;
546 #endif
547 ah->file = file;
548 ah->line = line;
549 #ifdef CHECK_XFLOWS
550 SET_XFLOW_MAGIC(ah);
551 #endif
553 ah->prev->next = ah;
554 ah->next->prev = ah;
556 dump_short_info(ah, file, line, "realloc");
558 return PTR_AH2BASE(ah);
561 void
562 set_mem_comment(void *ptr, const unsigned char *str, int len)
564 struct alloc_header *ah;
566 ah = PTR_BASE2AH(ptr);
568 if (ah->comment) {
569 mem_stats.true_amount -= strlen(ah->comment) + 1;
570 #ifdef CONFIG_GC
571 ah->comment = NULL;
572 #else
573 free(ah->comment);
574 #endif
576 #ifdef CONFIG_GC
577 ah->comment = GC_MALLOC(len + 1);
578 #else
579 ah->comment = malloc(len + 1);
580 #endif
581 if (ah->comment) {
582 memcpy(ah->comment, str, len);
583 ah->comment[len] = 0;
584 mem_stats.true_amount += len + 1;
588 #endif /* DEBUG_MEMLEAK */