mcheck.c revision 1.2 1 1.2 christos /* $NetBSD: mcheck.c,v 1.2 2016/01/13 21:56:38 christos Exp $ */
2 1.1 christos
3 1.1 christos /* Standard debugging hooks for `malloc'.
4 1.1 christos Copyright 1990, 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
5 1.1 christos Written May 1989 by Mike Haertel.
6 1.1 christos
7 1.1 christos This library is free software; you can redistribute it and/or
8 1.1 christos modify it under the terms of the GNU Library General Public License as
9 1.1 christos published by the Free Software Foundation; either version 2 of the
10 1.1 christos License, or (at your option) any later version.
11 1.1 christos
12 1.1 christos This library is distributed in the hope that it will be useful,
13 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of
14 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 1.1 christos Library General Public License for more details.
16 1.1 christos
17 1.1 christos You should have received a copy of the GNU Library General Public
18 1.1 christos License along with this library; see the file COPYING.LIB. If
19 1.1 christos not, write to the Free Software Foundation, Inc., 675 Mass Ave,
20 1.1 christos Cambridge, MA 02139, USA.
21 1.1 christos
22 1.1 christos The author may be reached (Email) at the address mike (at) ai.mit.edu,
23 1.1 christos or (US mail) as Mike Haertel c/o Free Software Foundation. */
24 1.1 christos
25 1.1 christos #ifndef _MALLOC_INTERNAL
26 1.1 christos #define _MALLOC_INTERNAL
27 1.1 christos #include <malloc.h>
28 1.2 christos #include <stdlib.h>
29 1.1 christos #include <stdio.h>
30 1.1 christos #endif
31 1.1 christos
32 1.1 christos /* Old hook values. */
33 1.1 christos static void (*old_free_hook) __P ((__ptr_t ptr));
34 1.1 christos static __ptr_t (*old_malloc_hook) __P ((__malloc_size_t size));
35 1.1 christos static __ptr_t (*old_realloc_hook) __P ((__ptr_t ptr, __malloc_size_t size));
36 1.1 christos
37 1.1 christos /* Function to call when something awful happens. */
38 1.1 christos static void (*abortfunc) __P ((enum mcheck_status));
39 1.1 christos
40 1.1 christos /* Arbitrary magical numbers. */
41 1.1 christos #define MAGICWORD 0xfedabeeb
42 1.1 christos #define MAGICFREE 0xd8675309
43 1.1 christos #define MAGICBYTE ((char) 0xd7)
44 1.1 christos #define MALLOCFLOOD ((char) 0x93)
45 1.1 christos #define FREEFLOOD ((char) 0x95)
46 1.1 christos
47 1.1 christos struct hdr
48 1.1 christos {
49 1.1 christos __malloc_size_t size; /* Exact size requested by user. */
50 1.1 christos unsigned long int magic; /* Magic number to check header integrity. */
51 1.1 christos };
52 1.1 christos
53 1.1 christos #if defined(_LIBC) || defined(STDC_HEADERS) || defined(USG)
54 1.1 christos #define flood memset
55 1.1 christos #else
56 1.1 christos static void flood __P ((__ptr_t, int, __malloc_size_t));
57 1.1 christos static void
58 1.1 christos flood (ptr, val, size)
59 1.1 christos __ptr_t ptr;
60 1.1 christos int val;
61 1.1 christos __malloc_size_t size;
62 1.1 christos {
63 1.1 christos char *cp = ptr;
64 1.1 christos while (size--)
65 1.1 christos *cp++ = val;
66 1.1 christos }
67 1.1 christos #endif
68 1.1 christos
69 1.1 christos static enum mcheck_status checkhdr __P ((const struct hdr *));
70 1.1 christos static enum mcheck_status
71 1.1 christos checkhdr (hdr)
72 1.1 christos const struct hdr *hdr;
73 1.1 christos {
74 1.1 christos enum mcheck_status status;
75 1.1 christos switch (hdr->magic)
76 1.1 christos {
77 1.1 christos default:
78 1.1 christos status = MCHECK_HEAD;
79 1.1 christos break;
80 1.1 christos case MAGICFREE:
81 1.1 christos status = MCHECK_FREE;
82 1.1 christos break;
83 1.1 christos case MAGICWORD:
84 1.1 christos if (((char *) &hdr[1])[hdr->size] != MAGICBYTE)
85 1.1 christos status = MCHECK_TAIL;
86 1.1 christos else
87 1.1 christos status = MCHECK_OK;
88 1.1 christos break;
89 1.1 christos }
90 1.1 christos if (status != MCHECK_OK)
91 1.1 christos (*abortfunc) (status);
92 1.1 christos return status;
93 1.1 christos }
94 1.1 christos
95 1.1 christos static void freehook __P ((__ptr_t));
96 1.1 christos static void
97 1.1 christos freehook (ptr)
98 1.1 christos __ptr_t ptr;
99 1.1 christos {
100 1.1 christos struct hdr *hdr = ((struct hdr *) ptr) - 1;
101 1.1 christos checkhdr (hdr);
102 1.1 christos hdr->magic = MAGICFREE;
103 1.1 christos flood (ptr, FREEFLOOD, hdr->size);
104 1.1 christos __free_hook = old_free_hook;
105 1.1 christos free (hdr);
106 1.1 christos __free_hook = freehook;
107 1.1 christos }
108 1.1 christos
109 1.1 christos static __ptr_t mallochook __P ((__malloc_size_t));
110 1.1 christos static __ptr_t
111 1.1 christos mallochook (size)
112 1.1 christos __malloc_size_t size;
113 1.1 christos {
114 1.1 christos struct hdr *hdr;
115 1.1 christos
116 1.1 christos __malloc_hook = old_malloc_hook;
117 1.1 christos hdr = (struct hdr *) malloc (sizeof (struct hdr) + size + 1);
118 1.1 christos __malloc_hook = mallochook;
119 1.1 christos if (hdr == NULL)
120 1.1 christos return NULL;
121 1.1 christos
122 1.1 christos hdr->size = size;
123 1.1 christos hdr->magic = MAGICWORD;
124 1.1 christos ((char *) &hdr[1])[size] = MAGICBYTE;
125 1.1 christos flood ((__ptr_t) (hdr + 1), MALLOCFLOOD, size);
126 1.1 christos return (__ptr_t) (hdr + 1);
127 1.1 christos }
128 1.1 christos
129 1.1 christos static __ptr_t reallochook __P ((__ptr_t, __malloc_size_t));
130 1.1 christos static __ptr_t
131 1.1 christos reallochook (ptr, size)
132 1.1 christos __ptr_t ptr;
133 1.1 christos __malloc_size_t size;
134 1.1 christos {
135 1.1 christos struct hdr *hdr = ((struct hdr *) ptr) - 1;
136 1.1 christos __malloc_size_t osize = hdr->size;
137 1.1 christos
138 1.1 christos checkhdr (hdr);
139 1.1 christos if (size < osize)
140 1.1 christos flood ((char *) ptr + size, FREEFLOOD, osize - size);
141 1.1 christos __free_hook = old_free_hook;
142 1.1 christos __malloc_hook = old_malloc_hook;
143 1.1 christos __realloc_hook = old_realloc_hook;
144 1.1 christos hdr = (struct hdr *) realloc ((__ptr_t) hdr, sizeof (struct hdr) + size + 1);
145 1.1 christos __free_hook = freehook;
146 1.1 christos __malloc_hook = mallochook;
147 1.1 christos __realloc_hook = reallochook;
148 1.1 christos if (hdr == NULL)
149 1.1 christos return NULL;
150 1.1 christos
151 1.1 christos hdr->size = size;
152 1.1 christos hdr->magic = MAGICWORD;
153 1.1 christos ((char *) &hdr[1])[size] = MAGICBYTE;
154 1.1 christos if (size > osize)
155 1.1 christos flood ((char *) (hdr + 1) + osize, MALLOCFLOOD, size - osize);
156 1.1 christos return (__ptr_t) (hdr + 1);
157 1.1 christos }
158 1.1 christos
159 1.1 christos static void
160 1.1 christos mabort (status)
161 1.1 christos enum mcheck_status status;
162 1.1 christos {
163 1.1 christos const char *msg;
164 1.1 christos switch (status)
165 1.1 christos {
166 1.1 christos case MCHECK_OK:
167 1.1 christos msg = "memory is consistent, library is buggy";
168 1.1 christos break;
169 1.1 christos case MCHECK_HEAD:
170 1.1 christos msg = "memory clobbered before allocated block";
171 1.1 christos break;
172 1.1 christos case MCHECK_TAIL:
173 1.1 christos msg = "memory clobbered past end of allocated block";
174 1.1 christos break;
175 1.1 christos case MCHECK_FREE:
176 1.1 christos msg = "block freed twice";
177 1.1 christos break;
178 1.1 christos default:
179 1.1 christos msg = "bogus mcheck_status, library is buggy";
180 1.1 christos break;
181 1.1 christos }
182 1.1 christos #ifdef __GNU_LIBRARY__
183 1.1 christos __libc_fatal (msg);
184 1.1 christos #else
185 1.1 christos fprintf (stderr, "mcheck: %s\n", msg);
186 1.1 christos fflush (stderr);
187 1.1 christos abort ();
188 1.1 christos #endif
189 1.1 christos }
190 1.1 christos
191 1.1 christos static int mcheck_used = 0;
192 1.1 christos
193 1.1 christos int
194 1.1 christos mcheck (func)
195 1.1 christos void (*func) __P ((enum mcheck_status));
196 1.1 christos {
197 1.1 christos abortfunc = (func != NULL) ? func : &mabort;
198 1.1 christos
199 1.1 christos /* These hooks may not be safely inserted if malloc is already in use. */
200 1.1 christos if (!__malloc_initialized && !mcheck_used)
201 1.1 christos {
202 1.1 christos old_free_hook = __free_hook;
203 1.1 christos __free_hook = freehook;
204 1.1 christos old_malloc_hook = __malloc_hook;
205 1.1 christos __malloc_hook = mallochook;
206 1.1 christos old_realloc_hook = __realloc_hook;
207 1.1 christos __realloc_hook = reallochook;
208 1.1 christos mcheck_used = 1;
209 1.1 christos }
210 1.1 christos
211 1.1 christos return mcheck_used ? 0 : -1;
212 1.1 christos }
213 1.1 christos
214 1.1 christos enum mcheck_status
215 1.1 christos mprobe (__ptr_t ptr)
216 1.1 christos {
217 1.1 christos return mcheck_used ? checkhdr (ptr) : MCHECK_DISABLED;
218 1.1 christos }
219