1 /*
2  * libc/stdlib/malloc/heap_debug.c -- optional heap debugging routines
3  *
4  *  Copyright (C) 2002  NEC Corporation
5  *  Copyright (C) 2002  Miles Bader <miles@gnu.org>
6  *
7  * This file is subject to the terms and conditions of the GNU Lesser
8  * General Public License.  See the file COPYING.LIB in the main
9  * directory of this archive for more details.
10  *
11  * Written by Miles Bader <miles@gnu.org>
12  */
13 
14 #include <stdlib.h>
15 #include <stdio.h>
16 #include <stdarg.h>
17 #include <string.h>
18 #include <unistd.h>
19 
20 
21 #include "malloc.h"
22 #include "heap.h"
23 
24 
25 #ifdef HEAP_DEBUGGING
26 int __heap_debug = 0;
27 #endif
28 
29 
30 static void
__heap_dump_freelist(struct heap_free_area * heap)31 __heap_dump_freelist (struct heap_free_area *heap)
32 {
33   struct heap_free_area *fa;
34   for (fa = heap; fa; fa = fa->next)
35     __malloc_debug_printf (0,
36 			   "0x%lx:  0x%lx - 0x%lx  (%d)\tP=0x%lx, N=0x%lx",
37 			   (long)fa,
38 			   (long)HEAP_FREE_AREA_START (fa),
39 			   (long)HEAP_FREE_AREA_END (fa),
40 			   fa->size,
41 			   (long)fa->prev,
42 			   (long)fa->next);
43 }
44 
45 /* Output a text representation of HEAP to stderr, labelling it with STR.  */
46 void
__heap_dump(struct heap_free_area * heap,const char * str)47 __heap_dump (struct heap_free_area *heap, const char *str)
48 {
49   static smallint recursed;
50 
51   if (! recursed)
52     {
53       __heap_check (heap, str);
54 
55       recursed = 1;
56 
57       __malloc_debug_printf (1, "%s: heap @0x%lx:", str, (long)heap);
58       __heap_dump_freelist (heap);
59       __malloc_debug_indent (-1);
60 
61       recursed = 0;
62     }
63 }
64 
65 
66 /* Output an error message to stderr, and exit.  STR is printed with the
67    failure message.  */
68 static void attribute_noreturn
__heap_check_failure(struct heap_free_area * heap,struct heap_free_area * fa,const char * str,char * fmt,...)69 __heap_check_failure (struct heap_free_area *heap, struct heap_free_area *fa,
70 		      const char *str, char *fmt, ...)
71 {
72   va_list val;
73 
74   if (str)
75     fprintf (stderr, "\nHEAP CHECK FAILURE %s: ", str);
76   else
77     fprintf (stderr, "\nHEAP CHECK FAILURE: ");
78 
79   va_start (val, fmt);
80   vfprintf (stderr, fmt, val);
81   va_end (val);
82 
83   fprintf (stderr, "\n");
84 
85   __malloc_debug_set_indent (0);
86   __malloc_debug_printf (1, "heap dump:");
87   __heap_dump_freelist (heap);
88 
89   _exit (22);
90 }
91 
92 /* Do some consistency checks on HEAP.  If they fail, output an error
93    message to stderr, and exit.  STR is printed with the failure message.  */
94 void
__heap_check(struct heap_free_area * heap,const char * str)95 __heap_check (struct heap_free_area *heap, const char *str)
96 {
97   typedef unsigned long ul_t;
98   struct heap_free_area *fa, *prev;
99   struct heap_free_area *first_fa = heap;
100 
101   if (first_fa && first_fa->prev)
102     __heap_check_failure (heap, first_fa, str,
103 "first free-area has non-zero prev pointer:\n\
104     first free-area = 0x%lx\n\
105     (0x%lx)->prev   = 0x%lx\n",
106 			      (ul_t)first_fa,
107 			      (ul_t)first_fa, (ul_t)first_fa->prev);
108 
109   for (prev = 0, fa = first_fa; fa; prev = fa, fa = fa->next)
110     {
111       if (((ul_t)HEAP_FREE_AREA_END (fa) & (HEAP_GRANULARITY - 1))
112 	  || (fa->size & (HEAP_GRANULARITY - 1)))
113 	__heap_check_failure (heap, fa, str, "alignment error:\n\
114     (0x%lx)->start = 0x%lx\n\
115     (0x%lx)->size  = 0x%lx\n",
116 			      (ul_t)fa,
117 			      (ul_t)HEAP_FREE_AREA_START (fa),
118 			      (ul_t)fa, fa->size);
119 
120       if (fa->prev != prev)
121 	__heap_check_failure (heap, fa, str, "prev pointer corrupted:\n\
122     (0x%lx)->next = 0x%lx\n\
123     (0x%lx)->prev = 0x%lx\n",
124 			      (ul_t)prev, (ul_t)prev->next,
125 			      (ul_t)fa, (ul_t)fa->prev);
126 
127       if (prev)
128 	{
129 	  ul_t start = (ul_t)HEAP_FREE_AREA_START (fa);
130 	  ul_t prev_end = (ul_t)HEAP_FREE_AREA_END (prev);
131 
132 	  if (prev_end >= start)
133 	    __heap_check_failure (heap, fa, str,
134 				  "start %s with prev free-area end:\n\
135     (0x%lx)->prev  = 0x%lx\n\
136     (0x%lx)->start = 0x%lx\n\
137     (0x%lx)->end   = 0x%lx\n",
138 				  (prev_end == start ? "unmerged" : "overlaps"),
139 				  (ul_t)fa, (ul_t)prev,
140 				  (ul_t)fa, start,
141 				  (ul_t)prev, prev_end);
142 	}
143     }
144 }
145