1999-09-09 Federico Mena Quintero <federico@redhat.com>
[midnight-commander.git] / src / mad.c
blob61b5f6773a3314df3799574bb474a503667648a7
1 /* The Memory Allocation Debugging system
2 Copyright (C) 1994 Janne Kukonlehto.
4 To use MAD define HAVE_MAD and include "mad.h" in all the *.c files.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
20 #include <config.h>
21 #include "mad.h"
23 #undef tempnam
25 #undef malloc
26 #undef calloc
27 #undef realloc
28 #undef xmalloc
29 #undef strdup
30 #undef free
32 #undef g_malloc
33 #undef g_malloc0
34 #undef g_calloc
35 #undef g_realloc
36 #undef g_strdup
37 #undef g_free
39 #include <stdlib.h>
40 #include <stdio.h>
41 #include <string.h>
42 #include <signal.h> /* For kill() */
43 #ifdef HAVE_UNISTD_H
44 # include <unistd.h> /* For getpid() */
45 #endif
46 #include <glib.h>
48 /* Here to avoid non empty translation units */
49 #ifdef HAVE_MAD
51 /* Maximum number of memory area handles,
52 increase this if you run out of handles */
53 #define MAD_MAX_AREAS 10000
54 /* Maximum file name length */
55 #define MAD_MAX_FILE 50
56 /* Signature for detecting overwrites */
57 #define MAD_SIGNATURE (('M'<<24)|('a'<<16)|('d'<<8)|('S'))
59 typedef struct {
60 int in_use;
61 long *start_sig;
62 char file [MAD_MAX_FILE];
63 int line;
64 void *data;
65 long *end_sig;
66 } mad_mem_area;
68 static mad_mem_area mem_areas [MAD_MAX_AREAS];
69 static FILE *memlog = stderr;
71 void *watch_free_pointer = 0;
73 void mad_set_debug (char *file)
75 if((memlog=fopen (file, "w+")) == NULL)
76 memlog = stderr;
79 /* This function is only called by the mad_check function */
80 static void mad_abort (char *message, int area, char *file, int line)
82 fprintf (memlog, "MAD: %s in area %d.\r\n", message, area);
83 fprintf (memlog, " Allocated in file \"%s\" at line %d.\r\n",
84 mem_areas [area].file, mem_areas [area].line);
85 fprintf (memlog, " Discovered in file \"%s\" at line %d.\r\n",
86 file, line);
87 fprintf (memlog, "MAD: Core dumping...\r\n");
88 fflush (memlog);
89 kill (getpid (), 3);
92 /* Checks all the allocated memory areas.
93 This is called everytime memory is allocated or freed.
94 You can also call it anytime you think memory might be corrupted. */
95 void mad_check (char *file, int line)
97 int i;
99 for (i = 0; i < MAD_MAX_AREAS; i++){
100 if (! mem_areas [i].in_use)
101 continue;
102 if (*(mem_areas [i].start_sig) != MAD_SIGNATURE)
103 mad_abort ("Overwrite error: Bad start signature", i, file, line);
104 if (*(mem_areas [i].end_sig) != MAD_SIGNATURE)
105 mad_abort ("Overwrite error: Bad end signature", i, file, line);
107 fflush (memlog);
110 /* Allocates a memory area. Used instead of malloc and calloc. */
111 void *mad_alloc (int size, char *file, int line)
113 int i;
114 char *area;
116 mad_check (file, line);
118 for (i = 0; i < MAD_MAX_AREAS; i++){
119 if (! mem_areas [i].in_use)
120 break;
122 if (i >= MAD_MAX_AREAS){
123 fprintf (memlog, "MAD: Out of memory area handles. Increase the value of MAD_MAX_AREAS.\r\n");
124 fprintf (memlog, " Discovered in file \"%s\" at line %d.\r\n",
125 file, line);
126 fprintf (memlog, "MAD: Aborting...\r\n");
127 fflush (memlog);
128 abort ();
131 mem_areas [i].in_use = 1;
132 size = (size + 3) & (~3); /* Alignment */
133 area = (char*) g_malloc (size + 2 * sizeof (long));
134 if (!area){
135 fprintf (memlog, "MAD: Out of memory.\r\n");
136 fprintf (memlog, " Discovered in file \"%s\" at line %d.\r\n",
137 file, line);
138 fprintf (memlog, "MAD: Aborting...\r\n");
139 fflush (memlog);
140 abort ();
143 mem_areas [i].start_sig = (long*) area;
144 mem_areas [i].data = (area + sizeof (long));
145 mem_areas [i].end_sig = (long*) (area + size + sizeof (long));
146 *(mem_areas [i].start_sig) = MAD_SIGNATURE;
147 *(mem_areas [i].end_sig) = MAD_SIGNATURE;
149 if (strlen (file) >= MAD_MAX_FILE)
150 file [MAD_MAX_FILE - 1] = 0;
151 strcpy (mem_areas [i].file, file);
152 mem_areas [i].line = line;
154 return mem_areas [i].data;
157 /* Reallocates a memory area. Used instead of realloc. */
158 void *mad_realloc (void *ptr, int newsize, char *file, int line)
160 int i;
161 char *area;
163 if (!ptr)
164 return (mad_alloc (newsize, file, line));
166 mad_check (file, line);
168 for (i = 0; i < MAD_MAX_AREAS; i++){
169 if (! mem_areas [i].in_use)
170 continue;
171 if (mem_areas [i].data == ptr)
172 break;
174 if (i >= MAD_MAX_AREAS){
175 fprintf (memlog, "MAD: Attempted to realloc unallocated pointer: %p.\r\n", ptr);
176 fprintf (memlog, " Discovered in file \"%s\" at line %d.\r\n",
177 file, line);
178 fprintf (memlog, "MAD: Aborting...\r\n");
179 fflush (memlog);
180 abort ();
183 newsize = (newsize + 3) & (~3); /* Alignment */
184 area = (char*) g_realloc (mem_areas [i].start_sig, newsize + 2 * sizeof (long));
185 if (!area){
186 fprintf (memlog, "MAD: Out of memory.\r\n");
187 fprintf (memlog, " Discovered in file \"%s\" at line %d.\r\n",
188 file, line);
189 fprintf (memlog, "MAD: Aborting...\r\n");
190 fflush (memlog);
191 abort ();
194 mem_areas [i].start_sig = (long*) area;
195 mem_areas [i].data = (area + sizeof (long));
196 mem_areas [i].end_sig = (long*) (area + newsize + sizeof (long));
197 *(mem_areas [i].start_sig) = MAD_SIGNATURE;
198 *(mem_areas [i].end_sig) = MAD_SIGNATURE;
200 if (strlen (file) >= MAD_MAX_FILE)
201 file [MAD_MAX_FILE - 1] = 0;
202 strcpy (mem_areas [i].file, file);
203 mem_areas [i].line = line;
205 return mem_areas [i].data;
208 /* Allocates a memory area. Used instead of malloc and calloc. */
209 void *mad_alloc0 (int size, char *file, int line)
211 char *t;
213 t = (char *) mad_alloc (size, file, line);
214 memset (t, 0, size);
215 return (void *) t;
218 /* Duplicates a character string. Used instead of strdup. */
219 char *mad_strdup (const char *s, char *file, int line)
221 char *t;
223 t = (char *) mad_alloc (strlen (s) + 1, file, line);
224 strcpy (t, s);
225 return t;
228 /* Frees a memory area. Used instead of free. */
229 void mad_free (void *ptr, char *file, int line)
231 int i;
233 mad_check (file, line);
235 if (watch_free_pointer && ptr == watch_free_pointer){
236 fprintf (memlog, "MAD: Watch free pointer found in file \"%s\" at line %d.\r\n",
237 file, line);
238 fflush (memlog);
241 if (ptr == NULL){
242 fprintf (memlog, "MAD: Attempted to free a NULL pointer in file \"%s\" at line %d.\r\n",
243 file, line);
244 fflush (memlog);
245 return;
248 for (i = 0; i < MAD_MAX_AREAS; i++){
249 if (! mem_areas [i].in_use)
250 continue;
251 if (mem_areas [i].data == ptr)
252 break;
254 if (i >= MAD_MAX_AREAS){
255 fprintf (memlog, "MAD: Attempted to free an unallocated pointer: %p.\r\n", ptr);
256 fprintf (memlog, " Discovered in file \"%s\" at line %d.\r\n",
257 file, line);
258 fprintf (memlog, "MAD: Aborting...\r\n");
259 fflush (memlog);
260 abort ();
263 g_free (mem_areas [i].start_sig);
264 mem_areas [i].in_use = 0;
267 char *mad_tempnam (char *a, char *b)
269 char *t, *u;
270 t = tempnam(a,b); /* This malloc's internal buffer.. */
271 u = mad_strdup(t, "(mad_tempnam)", 0);
272 free(t);
273 return u;
276 /* Outputs a list of unfreed memory areas,
277 to be called as a last thing before exiting */
278 void mad_finalize (char *file, int line)
280 int i;
282 mad_check (file, line);
284 /* Following can be commented out if you don't want to see the
285 memory leaks of the Midnight Commander */
286 #if 1
287 for (i = 0; i < MAD_MAX_AREAS; i++){
288 if (! mem_areas [i].in_use)
289 continue;
290 fprintf (memlog, "MAD: Unfreed pointer: %p.\r\n", mem_areas [i].data);
291 fprintf (memlog, " Allocated in file \"%s\" at line %d.\r\n",
292 mem_areas [i].file, mem_areas [i].line);
293 fprintf (memlog, " Discovered in file \"%s\" at line %d.\r\n",
294 file, line);
295 fflush (memlog);
297 #endif
300 #endif /* HAVE_MAD */