* vfs.c (vfs_init) [!WITH_MCFS]: Don't register mcfs.
[midnight-commander.git] / src / mad.c
blob07bda38d11cbea3dc19ca6a8679ab8f28ba35e82
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. */
20 #include <config.h>
22 #ifdef HAVE_MAD
23 #include "mad.h"
25 #undef tempnam
27 #undef malloc
28 #undef calloc
29 #undef realloc
30 #undef xmalloc
31 #undef strdup
32 #undef strndup
33 #undef free
35 #undef g_malloc
36 #undef g_malloc0
37 #undef g_realloc
38 #undef g_strdup
39 #undef g_strndup
40 #undef g_free
41 #undef g_get_current_dir
43 #include <stdlib.h>
44 #include <stdio.h>
45 #include <string.h>
46 #include <signal.h> /* For kill() */
47 #ifdef HAVE_UNISTD_H
48 # include <unistd.h> /* For getpid() */
49 #endif
50 #include <glib.h>
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'))
60 typedef struct {
61 int in_use;
62 long *start_sig;
63 char file [MAD_MAX_FILE];
64 int line;
65 void *data;
66 long *end_sig;
67 } mad_mem_area;
69 static mad_mem_area *mem_areas;
70 static FILE *memlog;
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*/ {
76 int last_max_i;
77 long check_call_cnt;
78 } Stats = { -1, 0 } ;
80 void *watch_free_pointer = 0;
82 void
83 mad_init (void)
85 memlog = stderr;
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)
93 memlog = stderr;
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",
103 file, line);
104 fprintf (memlog, "MAD: Core dumping...\r\n");
105 fflush (memlog);
106 kill (getpid (), 3);
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)
112 if (NULL != ptr) {
113 fprintf(memlog, "MAD: %s: %p.\r\n", problem, ptr);
114 } else {
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");
119 fflush(memlog);
120 abort();
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)
128 int i;
130 if (--Mad_check_call_delay > 0)
131 return;
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)
136 continue;
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++;
143 fflush (memlog);
146 /* Allocates a memory area. Used instead of malloc and calloc. */
147 void *mad_alloc (int size, const char *file, int line)
149 int i;
150 char *area;
152 mad_check (file, line);
154 for (i = Alloc_idx_hint; i < MAD_MAX_AREAS; i++) {
155 if (! mem_areas [i].in_use)
156 break;
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));
172 if (!area)
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)
191 int i;
192 char *area;
194 if (!ptr)
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)
201 continue;
202 if (mem_areas [i].data == ptr)
203 break;
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));
210 if (!area)
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)
230 char *t;
232 t = (char *) mad_alloc (size, file, line);
233 memset (t, 0, size);
234 return (void *) t;
237 /* Duplicates a character string. Used instead of strdup. */
238 char *mad_strdup (const char *s, const char *file, int line)
240 if (s) {
241 char *t;
243 t = (char *) mad_alloc (strlen (s) + 1, file, line);
244 strcpy (t, s);
245 return t;
247 return NULL;
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)
254 if(s) {
255 char *new_str = mad_alloc(n + 1, file, line);
256 strncpy(new_str, s, n);
257 new_str[n] = '\0';
258 return new_str;
259 } else {
260 return NULL;
264 /* Frees a memory area. Used instead of free. */
265 void mad_free (void *ptr, const char *file, int line)
267 int i;
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",
273 file, line);
274 fflush (memlog);
277 if (ptr == NULL){
278 fprintf (memlog, "MAD: Attempted to free a NULL pointer in file \"%s\" at line %d.\r\n",
279 file, line);
280 fflush (memlog);
281 return;
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 )
287 goto found_it;
289 for ( i = MIN(Alloc_idx_hint+100, MAD_MAX_AREAS-1); i > Alloc_idx_hint; i-- )
290 if ( mem_areas [i].data == ptr )
291 goto found_it;
293 for (i = 0; i < MAD_MAX_AREAS; i++)
294 if ( mem_areas [i].data == ptr )
295 goto found_it;
297 mad_fatal_error("Attempted to free an unallocated pointer", ptr, file, line);
299 found_it:
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 )
305 Alloc_idx_hint = i;
308 char *mad_tempnam (char *a, char *b, const char *file, int line)
310 char *t, *u;
311 t = tempnam(a,b); /* This malloc's internal buffer.. */
312 u = mad_strdup(t, file, line);
313 free(t);
314 return u;
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)
321 int i;
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 */
328 #if 1
329 for (i = 0; i < MAD_MAX_AREAS; i++){
330 if (! mem_areas [i].in_use)
331 continue;
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",
336 file, line);
337 fflush (memlog);
339 fprintf(memlog,
340 "MAD: Stats -\n last_max_i:%d\n check_call_cnt:%ld\n",
341 Stats.last_max_i, Stats.check_call_cnt
343 #endif
346 char *
347 mad_strconcat (const char *first, ...)
349 va_list ap;
350 long len;
351 char *data, *result;
353 if (!first)
354 return 0;
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);
364 va_end (ap);
366 va_start (ap, first);
367 strcpy (result, first);
369 while ((data = va_arg (ap, char *)) != 0)
370 strcat (result, data);
372 va_end (ap);
374 return result;
378 /* These two functions grabbed from GLib's gstrfuncs.c */
379 char*
380 mad_strdup_vprintf (const char *format, va_list args1)
382 char *buffer;
383 va_list args2;
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);
390 va_end (args2);
392 return buffer;
395 char*
396 mad_strdup_printf (const char *format, ...)
398 char *buffer;
399 va_list args;
401 va_start (args, format);
402 buffer = mad_strdup_vprintf(format, args);
403 va_end (args);
405 return buffer;
408 char*
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);
413 g_free (cwd);
414 return ret;
416 #endif /* HAVE_MAD */