mcheck.c revision 1.1.1.1 1 1.1 christos /* $NetBSD: mcheck.c,v 1.1.1.1 2016/01/13 21:42:18 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.1 christos #include <stdio.h>
29 1.1 christos #endif
30 1.1 christos
31 1.1 christos /* Old hook values. */
32 1.1 christos static void (*old_free_hook) __P ((__ptr_t ptr));
33 1.1 christos static __ptr_t (*old_malloc_hook) __P ((__malloc_size_t size));
34 1.1 christos static __ptr_t (*old_realloc_hook) __P ((__ptr_t ptr, __malloc_size_t size));
35 1.1 christos
36 1.1 christos /* Function to call when something awful happens. */
37 1.1 christos static void (*abortfunc) __P ((enum mcheck_status));
38 1.1 christos
39 1.1 christos /* Arbitrary magical numbers. */
40 1.1 christos #define MAGICWORD 0xfedabeeb
41 1.1 christos #define MAGICFREE 0xd8675309
42 1.1 christos #define MAGICBYTE ((char) 0xd7)
43 1.1 christos #define MALLOCFLOOD ((char) 0x93)
44 1.1 christos #define FREEFLOOD ((char) 0x95)
45 1.1 christos
46 1.1 christos struct hdr
47 1.1 christos {
48 1.1 christos __malloc_size_t size; /* Exact size requested by user. */
49 1.1 christos unsigned long int magic; /* Magic number to check header integrity. */
50 1.1 christos };
51 1.1 christos
52 1.1 christos #if defined(_LIBC) || defined(STDC_HEADERS) || defined(USG)
53 1.1 christos #define flood memset
54 1.1 christos #else
55 1.1 christos static void flood __P ((__ptr_t, int, __malloc_size_t));
56 1.1 christos static void
57 1.1 christos flood (ptr, val, size)
58 1.1 christos __ptr_t ptr;
59 1.1 christos int val;
60 1.1 christos __malloc_size_t size;
61 1.1 christos {
62 1.1 christos char *cp = ptr;
63 1.1 christos while (size--)
64 1.1 christos *cp++ = val;
65 1.1 christos }
66 1.1 christos #endif
67 1.1 christos
68 1.1 christos static enum mcheck_status checkhdr __P ((const struct hdr *));
69 1.1 christos static enum mcheck_status
70 1.1 christos checkhdr (hdr)
71 1.1 christos const struct hdr *hdr;
72 1.1 christos {
73 1.1 christos enum mcheck_status status;
74 1.1 christos switch (hdr->magic)
75 1.1 christos {
76 1.1 christos default:
77 1.1 christos status = MCHECK_HEAD;
78 1.1 christos break;
79 1.1 christos case MAGICFREE:
80 1.1 christos status = MCHECK_FREE;
81 1.1 christos break;
82 1.1 christos case MAGICWORD:
83 1.1 christos if (((char *) &hdr[1])[hdr->size] != MAGICBYTE)
84 1.1 christos status = MCHECK_TAIL;
85 1.1 christos else
86 1.1 christos status = MCHECK_OK;
87 1.1 christos break;
88 1.1 christos }
89 1.1 christos if (status != MCHECK_OK)
90 1.1 christos (*abortfunc) (status);
91 1.1 christos return status;
92 1.1 christos }
93 1.1 christos
94 1.1 christos static void freehook __P ((__ptr_t));
95 1.1 christos static void
96 1.1 christos freehook (ptr)
97 1.1 christos __ptr_t ptr;
98 1.1 christos {
99 1.1 christos struct hdr *hdr = ((struct hdr *) ptr) - 1;
100 1.1 christos checkhdr (hdr);
101 1.1 christos hdr->magic = MAGICFREE;
102 1.1 christos flood (ptr, FREEFLOOD, hdr->size);
103 1.1 christos __free_hook = old_free_hook;
104 1.1 christos free (hdr);
105 1.1 christos __free_hook = freehook;
106 1.1 christos }
107 1.1 christos
108 1.1 christos static __ptr_t mallochook __P ((__malloc_size_t));
109 1.1 christos static __ptr_t
110 1.1 christos mallochook (size)
111 1.1 christos __malloc_size_t size;
112 1.1 christos {
113 1.1 christos struct hdr *hdr;
114 1.1 christos
115 1.1 christos __malloc_hook = old_malloc_hook;
116 1.1 christos hdr = (struct hdr *) malloc (sizeof (struct hdr) + size + 1);
117 1.1 christos __malloc_hook = mallochook;
118 1.1 christos if (hdr == NULL)
119 1.1 christos return NULL;
120 1.1 christos
121 1.1 christos hdr->size = size;
122 1.1 christos hdr->magic = MAGICWORD;
123 1.1 christos ((char *) &hdr[1])[size] = MAGICBYTE;
124 1.1 christos flood ((__ptr_t) (hdr + 1), MALLOCFLOOD, size);
125 1.1 christos return (__ptr_t) (hdr + 1);
126 1.1 christos }
127 1.1 christos
128 1.1 christos static __ptr_t reallochook __P ((__ptr_t, __malloc_size_t));
129 1.1 christos static __ptr_t
130 1.1 christos reallochook (ptr, size)
131 1.1 christos __ptr_t ptr;
132 1.1 christos __malloc_size_t size;
133 1.1 christos {
134 1.1 christos struct hdr *hdr = ((struct hdr *) ptr) - 1;
135 1.1 christos __malloc_size_t osize = hdr->size;
136 1.1 christos
137 1.1 christos checkhdr (hdr);
138 1.1 christos if (size < osize)
139 1.1 christos flood ((char *) ptr + size, FREEFLOOD, osize - size);
140 1.1 christos __free_hook = old_free_hook;
141 1.1 christos __malloc_hook = old_malloc_hook;
142 1.1 christos __realloc_hook = old_realloc_hook;
143 1.1 christos hdr = (struct hdr *) realloc ((__ptr_t) hdr, sizeof (struct hdr) + size + 1);
144 1.1 christos __free_hook = freehook;
145 1.1 christos __malloc_hook = mallochook;
146 1.1 christos __realloc_hook = reallochook;
147 1.1 christos if (hdr == NULL)
148 1.1 christos return NULL;
149 1.1 christos
150 1.1 christos hdr->size = size;
151 1.1 christos hdr->magic = MAGICWORD;
152 1.1 christos ((char *) &hdr[1])[size] = MAGICBYTE;
153 1.1 christos if (size > osize)
154 1.1 christos flood ((char *) (hdr + 1) + osize, MALLOCFLOOD, size - osize);
155 1.1 christos return (__ptr_t) (hdr + 1);
156 1.1 christos }
157 1.1 christos
158 1.1 christos static void
159 1.1 christos mabort (status)
160 1.1 christos enum mcheck_status status;
161 1.1 christos {
162 1.1 christos const char *msg;
163 1.1 christos switch (status)
164 1.1 christos {
165 1.1 christos case MCHECK_OK:
166 1.1 christos msg = "memory is consistent, library is buggy";
167 1.1 christos break;
168 1.1 christos case MCHECK_HEAD:
169 1.1 christos msg = "memory clobbered before allocated block";
170 1.1 christos break;
171 1.1 christos case MCHECK_TAIL:
172 1.1 christos msg = "memory clobbered past end of allocated block";
173 1.1 christos break;
174 1.1 christos case MCHECK_FREE:
175 1.1 christos msg = "block freed twice";
176 1.1 christos break;
177 1.1 christos default:
178 1.1 christos msg = "bogus mcheck_status, library is buggy";
179 1.1 christos break;
180 1.1 christos }
181 1.1 christos #ifdef __GNU_LIBRARY__
182 1.1 christos __libc_fatal (msg);
183 1.1 christos #else
184 1.1 christos fprintf (stderr, "mcheck: %s\n", msg);
185 1.1 christos fflush (stderr);
186 1.1 christos abort ();
187 1.1 christos #endif
188 1.1 christos }
189 1.1 christos
190 1.1 christos static int mcheck_used = 0;
191 1.1 christos
192 1.1 christos int
193 1.1 christos mcheck (func)
194 1.1 christos void (*func) __P ((enum mcheck_status));
195 1.1 christos {
196 1.1 christos abortfunc = (func != NULL) ? func : &mabort;
197 1.1 christos
198 1.1 christos /* These hooks may not be safely inserted if malloc is already in use. */
199 1.1 christos if (!__malloc_initialized && !mcheck_used)
200 1.1 christos {
201 1.1 christos old_free_hook = __free_hook;
202 1.1 christos __free_hook = freehook;
203 1.1 christos old_malloc_hook = __malloc_hook;
204 1.1 christos __malloc_hook = mallochook;
205 1.1 christos old_realloc_hook = __realloc_hook;
206 1.1 christos __realloc_hook = reallochook;
207 1.1 christos mcheck_used = 1;
208 1.1 christos }
209 1.1 christos
210 1.1 christos return mcheck_used ? 0 : -1;
211 1.1 christos }
212 1.1 christos
213 1.1 christos enum mcheck_status
214 1.1 christos mprobe (__ptr_t ptr)
215 1.1 christos {
216 1.1 christos return mcheck_used ? checkhdr (ptr) : MCHECK_DISABLED;
217 1.1 christos }
218