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. */
42 #include <signal.h> /* For kill() */
44 # include <unistd.h> /* For getpid() */
48 /* Here to avoid non empty translation units */
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'))
62 char file
[MAD_MAX_FILE
];
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
)
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",
87 fprintf (memlog
, "MAD: Core dumping...\r\n");
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
)
99 for (i
= 0; i
< MAD_MAX_AREAS
; i
++){
100 if (! mem_areas
[i
].in_use
)
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
);
110 /* Allocates a memory area. Used instead of malloc and calloc. */
111 void *mad_alloc (int size
, char *file
, int line
)
116 mad_check (file
, line
);
118 for (i
= 0; i
< MAD_MAX_AREAS
; i
++){
119 if (! mem_areas
[i
].in_use
)
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",
126 fprintf (memlog
, "MAD: Aborting...\r\n");
131 mem_areas
[i
].in_use
= 1;
132 size
= (size
+ 3) & (~3); /* Alignment */
133 area
= (char*) g_malloc (size
+ 2 * sizeof (long));
135 fprintf (memlog
, "MAD: Out of memory.\r\n");
136 fprintf (memlog
, " Discovered in file \"%s\" at line %d.\r\n",
138 fprintf (memlog
, "MAD: Aborting...\r\n");
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
)
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
)
171 if (mem_areas
[i
].data
== ptr
)
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",
178 fprintf (memlog
, "MAD: Aborting...\r\n");
183 newsize
= (newsize
+ 3) & (~3); /* Alignment */
184 area
= (char*) g_realloc (mem_areas
[i
].start_sig
, newsize
+ 2 * sizeof (long));
186 fprintf (memlog
, "MAD: Out of memory.\r\n");
187 fprintf (memlog
, " Discovered in file \"%s\" at line %d.\r\n",
189 fprintf (memlog
, "MAD: Aborting...\r\n");
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
)
213 t
= (char *) mad_alloc (size
, file
, line
);
218 /* Duplicates a character string. Used instead of strdup. */
219 char *mad_strdup (const char *s
, char *file
, int line
)
223 t
= (char *) mad_alloc (strlen (s
) + 1, file
, line
);
228 /* Frees a memory area. Used instead of free. */
229 void mad_free (void *ptr
, char *file
, int line
)
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",
242 fprintf (memlog
, "MAD: Attempted to free a NULL pointer in file \"%s\" at line %d.\r\n",
248 for (i
= 0; i
< MAD_MAX_AREAS
; i
++){
249 if (! mem_areas
[i
].in_use
)
251 if (mem_areas
[i
].data
== ptr
)
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",
258 fprintf (memlog
, "MAD: Aborting...\r\n");
263 g_free (mem_areas
[i
].start_sig
);
264 mem_areas
[i
].in_use
= 0;
267 char *mad_tempnam (char *a
, char *b
)
270 t
= tempnam(a
,b
); /* This malloc's internal buffer.. */
271 u
= mad_strdup(t
, "(mad_tempnam)", 0);
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
)
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 */
287 for (i
= 0; i
< MAD_MAX_AREAS
; i
++){
288 if (! mem_areas
[i
].in_use
)
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",
300 #endif /* HAVE_MAD */