Commit | Line | Data |
---|---|---|
1bbcbbe4 TC |
1 | #include "alloc.h" |
2 | #include <stdio.h> | |
3 | #include <errno.h> | |
4 | #include <stdarg.h> | |
e0b3527a | 5 | #include <string.h> |
1bbcbbe4 TC |
6 | |
7 | /* cheap version of Imager's logging */ | |
8 | char const *last_file; int last_line; | |
9 | ||
10 | static void do_log(int level, char const *fmt, ...); | |
11 | static | |
12 | void | |
13 | bndcheck(int idx); | |
14 | void | |
15 | bndcheck_all(void); | |
16 | ||
17 | #define mm_log(x) ((last_file = __FILE__), (last_line = __LINE__), do_log x ) | |
18 | ||
19 | #ifdef MEM_DEBUG | |
20 | ||
21 | #define MAXMAL 102400 | |
22 | #define MAXDESC 65 | |
23 | ||
24 | #define UNDRRNVAL 10 | |
25 | #define OVERRNVAL 10 | |
26 | ||
27 | #define PADBYTE 0xaa | |
28 | ||
29 | static int malloc_need_init = 1; | |
30 | ||
31 | void | |
32 | malloc_state(void); | |
33 | ||
34 | typedef struct { | |
35 | void* ptr; | |
36 | size_t size; | |
37 | char comm[MAXDESC]; | |
38 | } malloc_entry; | |
39 | ||
40 | malloc_entry malloc_pointers[MAXMAL]; | |
41 | ||
42 | ||
43 | ||
44 | /* Utility functions */ | |
45 | ||
46 | ||
47 | static | |
48 | void | |
49 | malloc_init(void) { | |
50 | int i; | |
51 | for(i=0; i<MAXMAL; i++) malloc_pointers[i].ptr = NULL; | |
52 | malloc_need_init = 0; | |
53 | atexit(malloc_state); | |
54 | } | |
55 | ||
56 | ||
57 | static | |
58 | int | |
59 | find_ptr(void *p) { | |
60 | int i; | |
61 | for(i=0;i<MAXMAL;i++) | |
62 | if (malloc_pointers[i].ptr == p) | |
63 | return i; | |
64 | return -1; | |
65 | } | |
66 | ||
67 | ||
68 | /* Takes a pointer to real start of array, | |
69 | * sets the entries in the table, returns | |
70 | * the offset corrected pointer */ | |
71 | ||
72 | static | |
73 | void * | |
74 | set_entry(int i, char *buf, size_t size, char const *file, int line) { | |
75 | memset( buf, PADBYTE, UNDRRNVAL ); | |
76 | memset( &buf[UNDRRNVAL+size], PADBYTE, OVERRNVAL ); | |
77 | buf += UNDRRNVAL; | |
78 | malloc_pointers[i].ptr = buf; | |
79 | malloc_pointers[i].size = size; | |
80 | sprintf(malloc_pointers[i].comm,"%s (%d)", file, line); | |
81 | return buf; | |
82 | } | |
83 | ||
84 | void | |
85 | malloc_state(void) { | |
86 | int i, total = 0; | |
87 | ||
88 | mm_log((0,"malloc_state()\n")); | |
89 | bndcheck_all(); | |
90 | for(i=0; i<MAXMAL; i++) if (malloc_pointers[i].ptr != NULL) { | |
91 | mm_log((0,"%d: %d (0x%x) : %s\n", i, malloc_pointers[i].size, malloc_pointers[i].ptr, malloc_pointers[i].comm)); | |
92 | total += malloc_pointers[i].size; | |
93 | } | |
94 | if (total == 0) mm_log((0,"No memory currently used!\n")); | |
95 | else mm_log((0,"total: %d\n",total)); | |
96 | } | |
97 | ||
98 | ||
99 | ||
100 | void* | |
101 | mymalloc_file_line(size_t size, char const* file, int line) { | |
102 | char *buf; | |
103 | int i; | |
104 | if (malloc_need_init) malloc_init(); | |
105 | ||
106 | /* bndcheck_all(); Uncomment for LOTS OF THRASHING */ | |
107 | ||
108 | if ( (i = find_ptr(NULL)) < 0 ) { | |
109 | mm_log((0,"more than %d segments allocated at %s (%d)\n", MAXMAL, file, line)); | |
110 | exit(3); | |
111 | } | |
112 | ||
113 | if ( (buf = malloc(size+UNDRRNVAL+OVERRNVAL)) == NULL ) { | |
114 | mm_log((1,"Unable to allocate %i for %s (%i)\n", size, file, line)); | |
115 | exit(3); | |
116 | } | |
117 | ||
118 | buf = set_entry(i, buf, size, file, line); | |
119 | mm_log((1,"mymalloc_file_line: slot <%d> %d bytes allocated at %p for %s (%d)\n", i, size, buf, file, line)); | |
120 | return buf; | |
121 | } | |
122 | ||
123 | void * | |
124 | (mymalloc)(int size) { | |
125 | return mymalloc_file_line(size, "unknown", 0); | |
126 | } | |
127 | ||
128 | void* | |
129 | myrealloc_file_line(void *ptr, size_t newsize, char const * file, int line) { | |
130 | char *buf; | |
131 | int i; | |
132 | ||
133 | if (malloc_need_init) malloc_init(); | |
134 | /* bndcheck_all(); ACTIVATE FOR LOTS OF THRASHING */ | |
135 | ||
136 | if (!ptr) { | |
137 | mm_log((1, "realloc called with ptr = NULL, sending request to malloc\n")); | |
138 | return mymalloc_file_line(newsize, file, line); | |
139 | } | |
140 | ||
141 | if (!newsize) { | |
142 | mm_log((1, "newsize = 0, sending request to free\n")); | |
143 | myfree_file_line(ptr, file, line); | |
144 | return NULL; | |
145 | } | |
146 | ||
147 | if ( (i = find_ptr(ptr)) == -1) { | |
148 | mm_log((0, "Unable to find %p in realloc for %s (%i)\n", ptr, file, line)); | |
149 | exit(3); | |
150 | } | |
151 | ||
152 | if ( (buf = realloc(((char *)ptr)-UNDRRNVAL, UNDRRNVAL+OVERRNVAL+newsize)) == NULL ) { | |
153 | mm_log((1,"Unable to reallocate %i bytes at %p for %s (%i)\n", newsize, ptr, file, line)); | |
154 | exit(3); | |
155 | } | |
156 | ||
157 | buf = set_entry(i, buf, newsize, file, line); | |
158 | mm_log((1,"realloc_file_line: slot <%d> %d bytes allocated at %p for %s (%d)\n", i, newsize, buf, file, line)); | |
159 | return buf; | |
160 | } | |
161 | ||
162 | void * | |
163 | (myrealloc)(void *ptr, size_t newsize) { | |
164 | return myrealloc_file_line(ptr, newsize, "unknown", 0); | |
165 | } | |
166 | ||
167 | static | |
168 | void | |
169 | bndcheck(int idx) { | |
170 | int i; | |
171 | size_t s = malloc_pointers[idx].size; | |
172 | unsigned char *pp = malloc_pointers[idx].ptr; | |
173 | if (!pp) { | |
174 | mm_log((1, "bndcheck: No pointer in slot %d\n", idx)); | |
175 | return; | |
176 | } | |
177 | ||
178 | for(i=0;i<UNDRRNVAL;i++) | |
179 | if (pp[-(1+i)] != PADBYTE) | |
180 | mm_log((1,"bndcheck: UNDERRUN OF %d bytes detected: slot = %d, point = %p, size = %d\n", i+1, idx, pp, s )); | |
181 | ||
182 | for(i=0;i<OVERRNVAL;i++) | |
183 | if (pp[s+i] != PADBYTE) | |
184 | mm_log((1,"bndcheck: OVERRUN OF %d bytes detected: slot = %d, point = %p, size = %d\n", i+1, idx, pp, s )); | |
185 | } | |
186 | ||
187 | void | |
188 | bndcheck_all(void) { | |
189 | int idx; | |
190 | mm_log((1, "bndcheck_all()\n")); | |
191 | for(idx=0; idx<MAXMAL; idx++) | |
192 | if (malloc_pointers[idx].ptr) | |
193 | bndcheck(idx); | |
194 | } | |
195 | ||
196 | void | |
197 | myfree_file_line(void *p, char const *file, int line) { | |
198 | char *pp = p; | |
199 | int match = 0; | |
200 | int i; | |
201 | ||
202 | for(i=0; i<MAXMAL; i++) if (malloc_pointers[i].ptr == p) { | |
203 | mm_log((1,"myfree_file_line: pointer %i (%s) freed at %s (%i)\n", i, malloc_pointers[i].comm, file, line)); | |
204 | bndcheck(i); | |
205 | malloc_pointers[i].ptr = NULL; | |
206 | match++; | |
207 | } | |
208 | ||
209 | mm_log((1, "myfree_file_line: freeing address %p (real %p) (%s:%d)\n", pp, pp-UNDRRNVAL, file, line)); | |
210 | ||
211 | if (match != 1) { | |
212 | mm_log((1, "myfree_file_line: INCONSISTENT REFCOUNT %d at %s (%i)\n", match, file, line)); | |
213 | fprintf(stderr, "myfree_file_line: INCONSISTENT REFCOUNT %d at %s (%i)\n", match, file, line); | |
214 | exit(255); | |
215 | } | |
216 | ||
217 | ||
218 | free(pp-UNDRRNVAL); | |
219 | } | |
220 | ||
221 | void | |
222 | (myfree)(void *block) { | |
223 | myfree_file_line(block, "unknown", 0); | |
224 | } | |
225 | ||
226 | #else | |
227 | ||
228 | #define malloc_comm(a,b) (mymalloc(a)) | |
229 | ||
230 | void | |
231 | malloc_state() { | |
232 | } | |
233 | ||
234 | void* | |
235 | mymalloc(size_t size) { | |
236 | void *buf; | |
237 | ||
238 | if (size < 0) { | |
239 | fprintf(stderr, "Attempt to allocate size %d\n", size); | |
240 | exit(3); | |
241 | } | |
242 | ||
243 | if ( (buf = malloc(size)) == NULL ) { | |
244 | mm_log((1, "mymalloc: unable to malloc %d\n", size)); | |
245 | fprintf(stderr,"Unable to malloc %d.\n", size); exit(3); | |
246 | } | |
247 | mm_log((1, "mymalloc(size %d) -> %p\n", size, buf)); | |
248 | return buf; | |
249 | } | |
250 | ||
251 | void * | |
252 | mymalloc_file_line(size_t size, char *file, int line) { | |
253 | return mymalloc(size); | |
254 | } | |
255 | ||
256 | void | |
257 | myfree(void *p) { | |
258 | mm_log((1, "myfree(p %p)\n", p)); | |
259 | free(p); | |
260 | } | |
261 | ||
262 | void | |
263 | myfree_file_line(void *p, char *file, int line) { | |
264 | myfree(p); | |
265 | } | |
266 | ||
267 | void * | |
268 | myrealloc(void *block, size_t size) { | |
269 | void *result; | |
270 | ||
271 | mm_log((1, "myrealloc(block %p, size %u)\n", block, size)); | |
272 | if ((result = realloc(block, size)) == NULL) { | |
273 | mm_log((1, "myrealloc: out of memory\n")); | |
274 | fprintf(stderr, "Out of memory.\n"); | |
275 | exit(3); | |
276 | } | |
277 | return result; | |
278 | } | |
279 | ||
280 | void * | |
281 | myrealloc_file_line(void *block, size_t newsize, char *file, int size) { | |
282 | return myrealloc(block, newsize); | |
283 | } | |
284 | ||
285 | #endif /* IMAGER_MALLOC_DEBUG */ | |
286 | ||
287 | FILE *log_file; | |
288 | ||
289 | void | |
290 | setup_log(void) { | |
291 | char *log_env = getenv("MEM_DEBUG"); | |
292 | if (!log_env) | |
293 | return; | |
294 | ||
295 | if (strcmp(log_env, "STDERR") == 0) { | |
296 | log_file = stderr; | |
297 | return; | |
298 | } | |
299 | log_file = fopen(log_env, "w+"); | |
300 | if (!log_file) { | |
301 | fprintf(stderr, "Could not open log %s: %s\n", log_env, strerror(errno)); | |
302 | exit(3); | |
303 | } | |
304 | } | |
305 | ||
306 | static void | |
307 | do_log(int level, char const *fmt, ...) { | |
308 | if (!log_file) setup_log(); | |
309 | ||
310 | if (log_file) { | |
311 | va_list ap; | |
312 | va_start(ap, fmt); | |
313 | fprintf(log_file, "[%s:%d] %d:", last_file, last_line, level); | |
314 | ||
315 | vfprintf(stderr, fmt, ap); | |
316 | va_end(ap); | |
317 | } | |
318 | } |