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