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. */
31 #include <signal.h> /* For kill() */
33 # include <unistd.h> /* For getpid() */
36 /* Here to avoid non empty translation units */
39 /* Maximum number of memory area handles,
40 increase this if you run out of handles */
41 #define MAD_MAX_AREAS 3000
42 /* Maximum file name length */
43 #define MAD_MAX_FILE 50
44 /* Signature for detecting overwrites */
45 #define MAD_SIGNATURE (('M'<<24)|('a'<<16)|('d'<<8)|('S'))
50 char file
[MAD_MAX_FILE
];
56 static mad_mem_area mem_areas
[MAD_MAX_AREAS
];
57 void *watch_free_pointer
= 0;
59 /* This function is only called by the mad_check function */
60 static void mad_abort (char *message
, int area
, char *file
, int line
)
62 fprintf (stderr
, "MAD: %s in area %d.\r\n", message
, area
);
63 fprintf (stderr
, " Allocated in file \"%s\" at line %d.\r\n",
64 mem_areas
[area
].file
, mem_areas
[area
].line
);
65 fprintf (stderr
, " Discovered in file \"%s\" at line %d.\r\n",
67 fprintf (stderr
, "MAD: Core dumping...\r\n");
71 /* Checks all the allocated memory areas.
72 This is called everytime memory is allocated or freed.
73 You can also call it anytime you think memory might be corrupted. */
74 void mad_check (char *file
, int line
)
78 for (i
= 0; i
< MAD_MAX_AREAS
; i
++){
79 if (! mem_areas
[i
].in_use
)
81 if (*(mem_areas
[i
].start_sig
) != MAD_SIGNATURE
)
82 mad_abort ("Overwrite error: Bad start signature", i
, file
, line
);
83 if (*(mem_areas
[i
].end_sig
) != MAD_SIGNATURE
)
84 mad_abort ("Overwrite error: Bad end signature", i
, file
, line
);
88 /* Allocates a memory area. Used instead of malloc and calloc. */
89 void *mad_alloc (int size
, char *file
, int line
)
94 mad_check (file
, line
);
96 for (i
= 0; i
< MAD_MAX_AREAS
; i
++){
97 if (! mem_areas
[i
].in_use
)
100 if (i
>= MAD_MAX_AREAS
){
101 fprintf (stderr
, "MAD: Out of memory area handles. Increase the value of MAD_MAX_AREAS.\r\n");
102 fprintf (stderr
, " Discovered in file \"%s\" at line %d.\r\n",
104 fprintf (stderr
, "MAD: Aborting...\r\n");
108 mem_areas
[i
].in_use
= 1;
109 size
= (size
+ 3) & (~3); /* Alignment */
110 area
= (char*) malloc (size
+ 2 * sizeof (long));
112 fprintf (stderr
, "MAD: Out of memory.\r\n");
113 fprintf (stderr
, " Discovered in file \"%s\" at line %d.\r\n",
115 fprintf (stderr
, "MAD: Aborting...\r\n");
119 mem_areas
[i
].start_sig
= (long*) area
;
120 mem_areas
[i
].data
= (area
+ sizeof (long));
121 mem_areas
[i
].end_sig
= (long*) (area
+ size
+ sizeof (long));
122 *(mem_areas
[i
].start_sig
) = MAD_SIGNATURE
;
123 *(mem_areas
[i
].end_sig
) = MAD_SIGNATURE
;
125 if (strlen (file
) >= MAD_MAX_FILE
)
126 file
[MAD_MAX_FILE
- 1] = 0;
127 strcpy (mem_areas
[i
].file
, file
);
128 mem_areas
[i
].line
= line
;
130 return mem_areas
[i
].data
;
133 /* Reallocates a memory area. Used instead of realloc. */
134 void *mad_realloc (void *ptr
, int newsize
, char *file
, int line
)
140 return (mad_alloc (newsize
, file
, line
));
142 mad_check (file
, line
);
144 for (i
= 0; i
< MAD_MAX_AREAS
; i
++){
145 if (! mem_areas
[i
].in_use
)
147 if (mem_areas
[i
].data
== ptr
)
150 if (i
>= MAD_MAX_AREAS
){
151 fprintf (stderr
, "MAD: Attempted to realloc unallocated pointer: %p.\r\n", ptr
);
152 fprintf (stderr
, " Discovered in file \"%s\" at line %d.\r\n",
154 fprintf (stderr
, "MAD: Aborting...\r\n");
158 newsize
= (newsize
+ 3) & (~3); /* Alignment */
159 area
= (char*) realloc (mem_areas
[i
].start_sig
, newsize
+ 2 * sizeof (long));
161 fprintf (stderr
, "MAD: Out of memory.\r\n");
162 fprintf (stderr
, " Discovered in file \"%s\" at line %d.\r\n",
164 fprintf (stderr
, "MAD: Aborting...\r\n");
168 mem_areas
[i
].start_sig
= (long*) area
;
169 mem_areas
[i
].data
= (area
+ sizeof (long));
170 mem_areas
[i
].end_sig
= (long*) (area
+ newsize
+ sizeof (long));
171 *(mem_areas
[i
].start_sig
) = MAD_SIGNATURE
;
172 *(mem_areas
[i
].end_sig
) = MAD_SIGNATURE
;
174 if (strlen (file
) >= MAD_MAX_FILE
)
175 file
[MAD_MAX_FILE
- 1] = 0;
176 strcpy (mem_areas
[i
].file
, file
);
177 mem_areas
[i
].line
= line
;
179 return mem_areas
[i
].data
;
182 /* Duplicates a character string. Used instead of strdup. */
183 char *mad_strdup (const char *s
, char *file
, int line
)
187 t
= (char *) mad_alloc (strlen (s
) + 1, file
, line
);
192 /* Frees a memory area. Used instead of free. */
193 void mad_free (void *ptr
, char *file
, int line
)
197 mad_check (file
, line
);
199 if (watch_free_pointer
&& ptr
== watch_free_pointer
){
200 printf ("watch free pointer found\n");
204 fprintf (stderr
, "MAD: Attempted to free a NULL pointer in file \"%s\" at line %d.\n",
209 for (i
= 0; i
< MAD_MAX_AREAS
; i
++){
210 if (! mem_areas
[i
].in_use
)
212 if (mem_areas
[i
].data
== ptr
)
215 if (i
>= MAD_MAX_AREAS
){
216 fprintf (stderr
, "MAD: Attempted to free an unallocated pointer: %p.\r\n", ptr
);
217 fprintf (stderr
, " Discovered in file \"%s\" at line %d.\r\n",
219 fprintf (stderr
, "MAD: Aborting...\r\n");
223 free (mem_areas
[i
].start_sig
);
224 mem_areas
[i
].in_use
= 0;
227 /* Outputs a list of unfreed memory areas,
228 to be called as a last thing before exiting */
229 void mad_finalize (char *file
, int line
)
233 mad_check (file
, line
);
235 /* Following can be commented out if you don't want to see the
236 memory leaks of the Midnight Commander */
238 for (i
= 0; i
< MAD_MAX_AREAS
; i
++){
239 if (! mem_areas
[i
].in_use
)
241 fprintf (stderr
, "MAD: Unfreed pointer: %p.\n", mem_areas
[i
].data
);
242 fprintf (stderr
, " Allocated in file \"%s\" at line %d.\r\n",
243 mem_areas
[i
].file
, mem_areas
[i
].line
);
244 fprintf (stderr
, " Discovered in file \"%s\" at line %d.\r\n",
250 #endif /* HAVE_MAD */