/* * libc/stdlib/malloc/heap_debug.c -- optional heap debugging routines * * Copyright (C) 2002 NEC Corporation * Copyright (C) 2002 Miles Bader <miles@gnu.org> * * This file is subject to the terms and conditions of the GNU Lesser * General Public License. See the file COPYING.LIB in the main * directory of this archive for more details. * * Written by Miles Bader <miles@gnu.org> */ #include <stdlib.h> #include <stdio.h> #include <stdarg.h> #include <string.h> #include <unistd.h> #include "malloc.h" #include "heap.h" #ifdef HEAP_DEBUGGING int __heap_debug = 0; #endif static void __heap_dump_freelist (struct heap_free_area *heap) { struct heap_free_area *fa; for (fa = heap; fa; fa = fa->next) __malloc_debug_printf (0, "0x%lx: 0x%lx - 0x%lx (%d)\tP=0x%lx, N=0x%lx", (long)fa, (long)HEAP_FREE_AREA_START (fa), (long)HEAP_FREE_AREA_END (fa), fa->size, (long)fa->prev, (long)fa->next); } /* Output a text representation of HEAP to stderr, labelling it with STR. */ void __heap_dump (struct heap_free_area *heap, const char *str) { static smallint recursed; if (! recursed) { __heap_check (heap, str); recursed = 1; __malloc_debug_printf (1, "%s: heap @0x%lx:", str, (long)heap); __heap_dump_freelist (heap); __malloc_debug_indent (-1); recursed = 0; } } /* Output an error message to stderr, and exit. STR is printed with the failure message. */ static void attribute_noreturn __heap_check_failure (struct heap_free_area *heap, struct heap_free_area *fa, const char *str, char *fmt, ...) { va_list val; if (str) fprintf (stderr, "\nHEAP CHECK FAILURE %s: ", str); else fprintf (stderr, "\nHEAP CHECK FAILURE: "); va_start (val, fmt); vfprintf (stderr, fmt, val); va_end (val); fprintf (stderr, "\n"); __malloc_debug_set_indent (0); __malloc_debug_printf (1, "heap dump:"); __heap_dump_freelist (heap); _exit (22); } /* Do some consistency checks on HEAP. If they fail, output an error message to stderr, and exit. STR is printed with the failure message. */ void __heap_check (struct heap_free_area *heap, const char *str) { typedef unsigned long ul_t; struct heap_free_area *fa, *prev; struct heap_free_area *first_fa = heap; if (first_fa && first_fa->prev) __heap_check_failure (heap, first_fa, str, "first free-area has non-zero prev pointer:\n\ first free-area = 0x%lx\n\ (0x%lx)->prev = 0x%lx\n", (ul_t)first_fa, (ul_t)first_fa, (ul_t)first_fa->prev); for (prev = 0, fa = first_fa; fa; prev = fa, fa = fa->next) { if (((ul_t)HEAP_FREE_AREA_END (fa) & (HEAP_GRANULARITY - 1)) || (fa->size & (HEAP_GRANULARITY - 1))) __heap_check_failure (heap, fa, str, "alignment error:\n\ (0x%lx)->start = 0x%lx\n\ (0x%lx)->size = 0x%lx\n", (ul_t)fa, (ul_t)HEAP_FREE_AREA_START (fa), (ul_t)fa, fa->size); if (fa->prev != prev) __heap_check_failure (heap, fa, str, "prev pointer corrupted:\n\ (0x%lx)->next = 0x%lx\n\ (0x%lx)->prev = 0x%lx\n", (ul_t)prev, (ul_t)prev->next, (ul_t)fa, (ul_t)fa->prev); if (prev) { ul_t start = (ul_t)HEAP_FREE_AREA_START (fa); ul_t prev_end = (ul_t)HEAP_FREE_AREA_END (prev); if (prev_end >= start) __heap_check_failure (heap, fa, str, "start %s with prev free-area end:\n\ (0x%lx)->prev = 0x%lx\n\ (0x%lx)->start = 0x%lx\n\ (0x%lx)->end = 0x%lx\n", (prev_end == start ? "unmerged" : "overlaps"), (ul_t)fa, (ul_t)prev, (ul_t)fa, start, (ul_t)prev, prev_end); } } }