Sync to Wine-0_9_5:
[reactos.git] / rosapps / mc / src / mad.c
1 /* The Memory Allocation Debugging system
2 Copyright (C) 1994 Janne Kukonlehto.
3
4 To use MAD define HAVE_MAD and include "mad.h" in all the *.c files.
5
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.
10
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.
15
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. */
19
20 #include <config.h>
21 #include "mad.h"
22 #undef malloc
23 #undef calloc
24 #undef realloc
25 #undef xmalloc
26 #undef strdup
27 #undef free
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <signal.h> /* For kill() */
32 #ifdef HAVE_UNISTD_H
33 # include <unistd.h> /* For getpid() */
34 #endif
35
36 /* Here to avoid non empty translation units */
37 #ifdef HAVE_MAD
38
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'))
46
47 typedef struct {
48 int in_use;
49 long *start_sig;
50 char file [MAD_MAX_FILE];
51 int line;
52 void *data;
53 long *end_sig;
54 } mad_mem_area;
55
56 static mad_mem_area mem_areas [MAD_MAX_AREAS];
57 void *watch_free_pointer = 0;
58
59 /* This function is only called by the mad_check function */
60 static void mad_abort (char *message, int area, char *file, int line)
61 {
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",
66 file, line);
67 fprintf (stderr, "MAD: Core dumping...\r\n");
68 kill (getpid (), 3);
69 }
70
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)
75 {
76 int i;
77
78 for (i = 0; i < MAD_MAX_AREAS; i++){
79 if (! mem_areas [i].in_use)
80 continue;
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);
85 }
86 }
87
88 /* Allocates a memory area. Used instead of malloc and calloc. */
89 void *mad_alloc (int size, char *file, int line)
90 {
91 int i;
92 char *area;
93
94 mad_check (file, line);
95
96 for (i = 0; i < MAD_MAX_AREAS; i++){
97 if (! mem_areas [i].in_use)
98 break;
99 }
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",
103 file, line);
104 fprintf (stderr, "MAD: Aborting...\r\n");
105 abort ();
106 }
107
108 mem_areas [i].in_use = 1;
109 size = (size + 3) & (~3); /* Alignment */
110 area = (char*) malloc (size + 2 * sizeof (long));
111 if (!area){
112 fprintf (stderr, "MAD: Out of memory.\r\n");
113 fprintf (stderr, " Discovered in file \"%s\" at line %d.\r\n",
114 file, line);
115 fprintf (stderr, "MAD: Aborting...\r\n");
116 abort ();
117 }
118
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;
124
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;
129
130 return mem_areas [i].data;
131 }
132
133 /* Reallocates a memory area. Used instead of realloc. */
134 void *mad_realloc (void *ptr, int newsize, char *file, int line)
135 {
136 int i;
137 char *area;
138
139 if (!ptr)
140 return (mad_alloc (newsize, file, line));
141
142 mad_check (file, line);
143
144 for (i = 0; i < MAD_MAX_AREAS; i++){
145 if (! mem_areas [i].in_use)
146 continue;
147 if (mem_areas [i].data == ptr)
148 break;
149 }
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",
153 file, line);
154 fprintf (stderr, "MAD: Aborting...\r\n");
155 abort ();
156 }
157
158 newsize = (newsize + 3) & (~3); /* Alignment */
159 area = (char*) realloc (mem_areas [i].start_sig, newsize + 2 * sizeof (long));
160 if (!area){
161 fprintf (stderr, "MAD: Out of memory.\r\n");
162 fprintf (stderr, " Discovered in file \"%s\" at line %d.\r\n",
163 file, line);
164 fprintf (stderr, "MAD: Aborting...\r\n");
165 abort ();
166 }
167
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;
173
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;
178
179 return mem_areas [i].data;
180 }
181
182 /* Duplicates a character string. Used instead of strdup. */
183 char *mad_strdup (const char *s, char *file, int line)
184 {
185 char *t;
186
187 t = (char *) mad_alloc (strlen (s) + 1, file, line);
188 strcpy (t, s);
189 return t;
190 }
191
192 /* Frees a memory area. Used instead of free. */
193 void mad_free (void *ptr, char *file, int line)
194 {
195 int i;
196
197 mad_check (file, line);
198
199 if (watch_free_pointer && ptr == watch_free_pointer){
200 printf ("watch free pointer found\n");
201 }
202
203 if (ptr == NULL){
204 fprintf (stderr, "MAD: Attempted to free a NULL pointer in file \"%s\" at line %d.\n",
205 file, line);
206 return;
207 }
208
209 for (i = 0; i < MAD_MAX_AREAS; i++){
210 if (! mem_areas [i].in_use)
211 continue;
212 if (mem_areas [i].data == ptr)
213 break;
214 }
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",
218 file, line);
219 fprintf (stderr, "MAD: Aborting...\r\n");
220 abort ();
221 }
222
223 free (mem_areas [i].start_sig);
224 mem_areas [i].in_use = 0;
225 }
226
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)
230 {
231 int i;
232
233 mad_check (file, line);
234
235 /* Following can be commented out if you don't want to see the
236 memory leaks of the Midnight Commander */
237 #if 1
238 for (i = 0; i < MAD_MAX_AREAS; i++){
239 if (! mem_areas [i].in_use)
240 continue;
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",
245 file, line);
246 }
247 #endif
248 }
249
250 #endif /* HAVE_MAD */