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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
41 #undef g_get_current_dir
46 #include <signal.h> /* For kill() */
48 # include <unistd.h> /* For getpid() */
52 /* Number of memory area handles currently allocated */
53 #define MAD_AREAS_STEP 10000
54 static int MAD_MAX_AREAS
= MAD_AREAS_STEP
;
55 /* Maximum file name length */
56 #define MAD_MAX_FILE 50
57 /* Signature for detecting overwrites */
58 #define MAD_SIGNATURE (('M'<<24)|('a'<<16)|('d'<<8)|('S'))
63 char file
[MAD_MAX_FILE
];
69 static mad_mem_area
*mem_areas
;
72 #define MAD_CHECK_CALL_FACTOR 30 /* Perform actual test every N call. */
73 static int Mad_check_call_delay
;
74 static int Alloc_idx_hint
= 0;
75 static struct /*mad_stats_struct*/ {
80 void *watch_free_pointer
= 0;
86 /* Here to prevent crash if mad_free or mad_realloc called before mad_alloc */
87 mem_areas
= g_new0 (mad_mem_area
, MAD_MAX_AREAS
);
90 void mad_set_debug (const char *file
)
92 if((memlog
=fopen (file
, "w+")) == NULL
)
96 /* This function is only called by the mad_check function */
97 static void mad_abort (const char *message
, int area
, const char *file
, int line
)
99 fprintf (memlog
, "MAD: %s in area %d.\r\n", message
, area
);
100 fprintf (memlog
, " Allocated in file \"%s\" at line %d.\r\n",
101 mem_areas
[area
].file
, mem_areas
[area
].line
);
102 fprintf (memlog
, " Discovered in file \"%s\" at line %d.\r\n",
104 fprintf (memlog
, "MAD: Core dumping...\r\n");
109 /* Code repeated in lots of places. Could be merged with mad_abort() above. */
110 static void mad_fatal_error(const char *problem
, void *ptr
, const char *file
, int line
)
113 fprintf(memlog
, "MAD: %s: %p.\r\n", problem
, ptr
);
115 fprintf(memlog
, "MAD: %s.\r\n", problem
);
117 fprintf(memlog
, " Discovered in file \"%s\" at line %d.\r\n", file
, line
);
118 fprintf(memlog
, "MAD: Aborting...\r\n");
123 /* Checks all the allocated memory areas.
124 This is called everytime memory is allocated or freed.
125 You can also call it anytime you think memory might be corrupted. */
126 void mad_check (const char *file
, int line
)
130 if (--Mad_check_call_delay
> 0)
132 Mad_check_call_delay
= MAD_CHECK_CALL_FACTOR
;
134 for (i
= 0; i
< MAD_MAX_AREAS
; i
++){
135 if (! mem_areas
[i
].in_use
)
137 if (*(mem_areas
[i
].start_sig
) != MAD_SIGNATURE
)
138 mad_abort ("Overwrite error: Bad start signature", i
, file
, line
);
139 if (*(mem_areas
[i
].end_sig
) != MAD_SIGNATURE
)
140 mad_abort ("Overwrite error: Bad end signature", i
, file
, line
);
142 Stats
.check_call_cnt
++;
146 /* Allocates a memory area. Used instead of malloc and calloc. */
147 void *mad_alloc (int size
, const char *file
, int line
)
152 mad_check (file
, line
);
154 for (i
= Alloc_idx_hint
; i
< MAD_MAX_AREAS
; i
++) {
155 if (! mem_areas
[i
].in_use
)
158 if (i
>= MAD_MAX_AREAS
) {
159 MAD_MAX_AREAS
+= MAD_AREAS_STEP
;
160 mem_areas
= g_realloc (mem_areas
, MAD_MAX_AREAS
* sizeof (mad_mem_area
));
161 if (mem_areas
== NULL
)
162 mad_fatal_error ("Out of memory area handles.", NULL
, file
, line
);
163 memset (mem_areas
+ i
, 0, MAD_AREAS_STEP
* sizeof (mad_mem_area
));
165 Alloc_idx_hint
= i
+1;
166 if (i
> Stats
.last_max_i
)
167 Stats
.last_max_i
= i
;
169 mem_areas
[i
].in_use
= 1;
170 size
= (size
+ 3) & (~3); /* Alignment */
171 area
= (char*) g_malloc (size
+ 2 * sizeof (long));
173 mad_fatal_error("Out of memory.", NULL
, file
, line
);
175 mem_areas
[i
].start_sig
= (long*) area
;
176 mem_areas
[i
].data
= (area
+ sizeof (long));
177 mem_areas
[i
].end_sig
= (long*) (area
+ size
+ sizeof (long));
178 *(mem_areas
[i
].start_sig
) = MAD_SIGNATURE
;
179 *(mem_areas
[i
].end_sig
) = MAD_SIGNATURE
;
181 strncpy (mem_areas
[i
].file
, file
, MAD_MAX_FILE
- 1);
182 mem_areas
[i
].file
[MAD_MAX_FILE
- 1] = 0;
183 mem_areas
[i
].line
= line
;
185 return mem_areas
[i
].data
;
188 /* Reallocates a memory area. Used instead of realloc. */
189 void *mad_realloc (void *ptr
, int newsize
, const char *file
, int line
)
195 return (mad_alloc (newsize
, file
, line
));
197 mad_check (file
, line
);
199 for (i
= 0; i
< MAD_MAX_AREAS
; i
++){
200 if (! mem_areas
[i
].in_use
)
202 if (mem_areas
[i
].data
== ptr
)
205 if (i
>= MAD_MAX_AREAS
)
206 mad_fatal_error("Attempted to realloc unallocated pointer", ptr
, file
, line
);
208 newsize
= (newsize
+ 3) & (~3); /* Alignment */
209 area
= (char*) g_realloc (mem_areas
[i
].start_sig
, newsize
+ 2 * sizeof (long));
211 mad_fatal_error("Out of memory", NULL
, file
, line
);
213 /* Reuses a position in mem_areas[] and thus does not set .in_use */
214 mem_areas
[i
].start_sig
= (long*) area
;
215 mem_areas
[i
].data
= (area
+ sizeof (long));
216 mem_areas
[i
].end_sig
= (long*) (area
+ newsize
+ sizeof (long));
217 *(mem_areas
[i
].start_sig
) = MAD_SIGNATURE
;
218 *(mem_areas
[i
].end_sig
) = MAD_SIGNATURE
;
220 strncpy (mem_areas
[i
].file
, file
, MAD_MAX_FILE
- 1);
221 mem_areas
[i
].file
[MAD_MAX_FILE
- 1] = 0;
222 mem_areas
[i
].line
= line
;
224 return mem_areas
[i
].data
;
227 /* Allocates a memory area. Used instead of malloc and calloc. */
228 void *mad_alloc0 (int size
, const char *file
, int line
)
232 t
= (char *) mad_alloc (size
, file
, line
);
237 /* Duplicates a character string. Used instead of strdup. */
238 char *mad_strdup (const char *s
, const char *file
, int line
)
243 t
= (char *) mad_alloc (strlen (s
) + 1, file
, line
);
250 /* Duplicates a character string. Used instead of strndup. */
251 /* Dup of GLib's gstrfuncs.c:g_strndup() */
252 char *mad_strndup (const char *s
, int n
, const char *file
, int line
)
255 char *new_str
= mad_alloc(n
+ 1, file
, line
);
256 strncpy(new_str
, s
, n
);
264 /* Frees a memory area. Used instead of free. */
265 void mad_free (void *ptr
, const char *file
, int line
)
269 mad_check (file
, line
);
271 if (watch_free_pointer
&& ptr
== watch_free_pointer
){
272 fprintf (memlog
, "MAD: Watch free pointer found in file \"%s\" at line %d.\r\n",
278 fprintf (memlog
, "MAD: Attempted to free a NULL pointer in file \"%s\" at line %d.\r\n",
284 /* Do a quick search in the neighborhood of Alloc_idx_hint. */
285 for ( i
= MAX(Alloc_idx_hint
-100, 0); i
<= Alloc_idx_hint
; i
++ )
286 if ( mem_areas
[i
].data
== ptr
)
289 for ( i
= MIN(Alloc_idx_hint
+100, MAD_MAX_AREAS
-1); i
> Alloc_idx_hint
; i
-- )
290 if ( mem_areas
[i
].data
== ptr
)
293 for (i
= 0; i
< MAD_MAX_AREAS
; i
++)
294 if ( mem_areas
[i
].data
== ptr
)
297 mad_fatal_error("Attempted to free an unallocated pointer", ptr
, file
, line
);
300 g_free (mem_areas
[i
].start_sig
);
301 mem_areas
[i
].in_use
= 0;
303 mem_areas
[i
].data
= NULL
; /* Kill the pointer - no need to check .in_use above.*/
304 if ( i
< Alloc_idx_hint
)
308 char *mad_tempnam (char *a
, char *b
, const char *file
, int line
)
311 t
= tempnam(a
,b
); /* This malloc's internal buffer.. */
312 u
= mad_strdup(t
, file
, line
);
317 /* Outputs a list of unfreed memory areas,
318 to be called as a last thing before exiting */
319 void mad_finalize (const char *file
, int line
)
323 Mad_check_call_delay
= 0;
324 mad_check (file
, line
);
326 /* Following can be commented out if you don't want to see the
327 memory leaks of the Midnight Commander */
329 for (i
= 0; i
< MAD_MAX_AREAS
; i
++){
330 if (! mem_areas
[i
].in_use
)
332 fprintf (memlog
, "MAD: Unfreed pointer: %p.\r\n", mem_areas
[i
].data
);
333 fprintf (memlog
, " Allocated in file \"%s\" at line %d.\r\n",
334 mem_areas
[i
].file
, mem_areas
[i
].line
);
335 fprintf (memlog
, " Discovered in file \"%s\" at line %d.\r\n",
340 "MAD: Stats -\n last_max_i:%d\n check_call_cnt:%ld\n",
341 Stats
.last_max_i
, Stats
.check_call_cnt
347 mad_strconcat (const char *first
, ...)
356 len
= strlen (first
) + 1;
357 va_start (ap
, first
);
359 while ((data
= va_arg (ap
, char *)) != 0)
360 len
+= strlen (data
);
362 result
= mad_alloc(len
, "(mad_strconcat)", 0);
366 va_start (ap
, first
);
367 strcpy (result
, first
);
369 while ((data
= va_arg (ap
, char *)) != 0)
370 strcat (result
, data
);
378 /* These two functions grabbed from GLib's gstrfuncs.c */
380 mad_strdup_vprintf (const char *format
, va_list args1
)
385 G_VA_COPY (args2
, args1
);
387 buffer
= mad_alloc(g_printf_string_upper_bound(format
, args1
), "(mad_strdup_vprintf)", 0);
389 vsprintf (buffer
, format
, args2
);
396 mad_strdup_printf (const char *format
, ...)
401 va_start (args
, format
);
402 buffer
= mad_strdup_vprintf(format
, args
);
409 mad_get_current_dir (const char *file
, int line
)
411 char *cwd
= g_get_current_dir ();
412 char *ret
= mad_strdup (cwd
, file
, line
);
416 #endif /* HAVE_MAD */