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