Commit | Line | Data |
---|---|---|
e310e5f9 | 1 | #include "imager.h" |
02d1d628 AMH |
2 | #include <stdlib.h> |
3 | #ifndef _MSC_VER | |
4 | #include <unistd.h> | |
5 | #endif | |
6 | ||
7 | ||
8 | /* FIXME: make allocation dynamic */ | |
9 | ||
10 | ||
11 | #ifdef IMAGER_DEBUG_MALLOC | |
12 | ||
2ff8ed30 | 13 | #define MAXMAL 102400 |
02d1d628 AMH |
14 | #define MAXDESC 65 |
15 | ||
a743c0a6 AMH |
16 | #define UNDRRNVAL 10 |
17 | #define OVERRNVAL 10 | |
02d1d628 AMH |
18 | |
19 | #define PADBYTE 0xaa | |
20 | ||
21 | ||
22 | static int malloc_need_init = 1; | |
23 | ||
24 | typedef struct { | |
fe6163bf | 25 | void* ptr; |
02d1d628 | 26 | size_t size; |
fe6163bf | 27 | char comm[MAXDESC]; |
02d1d628 AMH |
28 | } malloc_entry; |
29 | ||
30 | malloc_entry malloc_pointers[MAXMAL]; | |
31 | ||
fe6163bf AMH |
32 | |
33 | ||
34 | ||
35 | /* Utility functions */ | |
36 | ||
37 | ||
38 | static | |
39 | void | |
aea697ad | 40 | malloc_init(void) { |
fe6163bf AMH |
41 | int i; |
42 | for(i=0; i<MAXMAL; i++) malloc_pointers[i].ptr = NULL; | |
43 | malloc_need_init = 0; | |
44 | atexit(malloc_state); | |
45 | } | |
46 | ||
47 | ||
48 | static | |
49 | int | |
50 | find_ptr(void *p) { | |
51 | int i; | |
52 | for(i=0;i<MAXMAL;i++) | |
53 | if (malloc_pointers[i].ptr == p) | |
54 | return i; | |
55 | return -1; | |
56 | } | |
57 | ||
58 | ||
59 | /* Takes a pointer to real start of array, | |
60 | * sets the entries in the table, returns | |
61 | * the offset corrected pointer */ | |
62 | ||
63 | static | |
64 | void * | |
65 | set_entry(int i, char *buf, size_t size, char *file, int line) { | |
66 | memset( buf, PADBYTE, UNDRRNVAL ); | |
67 | memset( &buf[UNDRRNVAL+size], PADBYTE, OVERRNVAL ); | |
68 | buf += UNDRRNVAL; | |
69 | malloc_pointers[i].ptr = buf; | |
70 | malloc_pointers[i].size = size; | |
71 | sprintf(malloc_pointers[i].comm,"%s (%d)", file, line); | |
72 | return buf; | |
73 | } | |
74 | ||
02d1d628 | 75 | void |
aea697ad | 76 | malloc_state(void) { |
fe6163bf AMH |
77 | int i, total = 0; |
78 | ||
cd4b0b20 | 79 | i_clear_error(); |
02d1d628 AMH |
80 | mm_log((0,"malloc_state()\n")); |
81 | bndcheck_all(); | |
fe6163bf AMH |
82 | for(i=0; i<MAXMAL; i++) if (malloc_pointers[i].ptr != NULL) { |
83 | mm_log((0,"%d: %d (0x%x) : %s\n", i, malloc_pointers[i].size, malloc_pointers[i].ptr, malloc_pointers[i].comm)); | |
84 | total += malloc_pointers[i].size; | |
02d1d628 | 85 | } |
fe6163bf AMH |
86 | if (total == 0) mm_log((0,"No memory currently used!\n")) |
87 | else mm_log((0,"total: %d\n",total)); | |
02d1d628 AMH |
88 | } |
89 | ||
90 | ||
fe6163bf | 91 | |
02d1d628 | 92 | void* |
fe6163bf | 93 | mymalloc_file_line(size_t size, char* file, int line) { |
02d1d628 AMH |
94 | char *buf; |
95 | int i; | |
fe6163bf AMH |
96 | if (malloc_need_init) malloc_init(); |
97 | ||
98 | /* bndcheck_all(); Uncomment for LOTS OF THRASHING */ | |
99 | ||
100 | if ( (i = find_ptr(NULL)) < 0 ) { | |
101 | mm_log((0,"more than %d segments allocated at %s (%d)\n", MAXMAL, file, line)); | |
102 | exit(3); | |
02d1d628 AMH |
103 | } |
104 | ||
fe6163bf AMH |
105 | if ( (buf = malloc(size+UNDRRNVAL+OVERRNVAL)) == NULL ) { |
106 | mm_log((1,"Unable to allocate %i for %s (%i)\n", size, file, line)); | |
107 | exit(3); | |
02d1d628 AMH |
108 | } |
109 | ||
fe6163bf AMH |
110 | buf = set_entry(i, buf, size, file, line); |
111 | mm_log((1,"mymalloc_file_line: slot <%d> %d bytes allocated at %p for %s (%d)\n", i, size, buf, file, line)); | |
112 | return buf; | |
02d1d628 AMH |
113 | } |
114 | ||
e310e5f9 TC |
115 | void * |
116 | (mymalloc)(int size) { | |
117 | return mymalloc_file_line(size, "unknown", 0); | |
118 | } | |
119 | ||
02d1d628 | 120 | void* |
fe6163bf AMH |
121 | myrealloc_file_line(void *ptr, size_t newsize, char* file, int line) { |
122 | char *buf; | |
02d1d628 | 123 | int i; |
fe6163bf AMH |
124 | |
125 | if (malloc_need_init) malloc_init(); | |
126 | /* bndcheck_all(); ACTIVATE FOR LOTS OF THRASHING */ | |
127 | ||
128 | if (!ptr) { | |
129 | mm_log((1, "realloc called with ptr = NULL, sending request to malloc\n")); | |
130 | return mymalloc_file_line(newsize, file, line); | |
02d1d628 AMH |
131 | } |
132 | ||
fe6163bf AMH |
133 | if (!newsize) { |
134 | mm_log((1, "newsize = 0, sending request to free\n")); | |
135 | myfree_file_line(ptr, file, line); | |
136 | return NULL; | |
137 | } | |
02d1d628 | 138 | |
fe6163bf AMH |
139 | if ( (i = find_ptr(ptr)) == -1) { |
140 | mm_log((0, "Unable to find %p in realloc for %s (%i)\n", ptr, file, line)); | |
141 | exit(3); | |
142 | } | |
143 | ||
aea697ad | 144 | if ( (buf = realloc(((char *)ptr)-UNDRRNVAL, UNDRRNVAL+OVERRNVAL+newsize)) == NULL ) { |
fe6163bf AMH |
145 | mm_log((1,"Unable to reallocate %i bytes at %p for %s (%i)\n", newsize, ptr, file, line)); |
146 | exit(3); | |
02d1d628 | 147 | } |
fe6163bf AMH |
148 | |
149 | buf = set_entry(i, buf, newsize, file, line); | |
150 | mm_log((1,"realloc_file_line: slot <%d> %d bytes allocated at %p for %s (%d)\n", i, newsize, buf, file, line)); | |
151 | return buf; | |
02d1d628 | 152 | } |
fe6163bf | 153 | |
e310e5f9 TC |
154 | void * |
155 | (myrealloc)(void *ptr, size_t newsize) { | |
156 | return myrealloc_file_line(ptr, newsize, "unknown", 0); | |
157 | } | |
158 | ||
02d1d628 AMH |
159 | static |
160 | void | |
161 | bndcheck(int idx) { | |
162 | int i; | |
163 | size_t s = malloc_pointers[idx].size; | |
fe6163bf | 164 | unsigned char *pp = malloc_pointers[idx].ptr; |
02d1d628 AMH |
165 | if (!pp) { |
166 | mm_log((1, "bndcheck: No pointer in slot %d\n", idx)); | |
167 | return; | |
168 | } | |
169 | ||
170 | for(i=0;i<UNDRRNVAL;i++) | |
fe6163bf AMH |
171 | if (pp[-(1+i)] != PADBYTE) |
172 | mm_log((1,"bndcheck: UNDERRUN OF %d bytes detected: slot = %d, point = %p, size = %d\n", i+1, idx, pp, s )); | |
02d1d628 | 173 | |
fe6163bf | 174 | for(i=0;i<OVERRNVAL;i++) |
02d1d628 AMH |
175 | if (pp[s+i] != PADBYTE) |
176 | mm_log((1,"bndcheck: OVERRUN OF %d bytes detected: slot = %d, point = %p, size = %d\n", i+1, idx, pp, s )); | |
177 | } | |
178 | ||
179 | void | |
180 | bndcheck_all() { | |
181 | int idx; | |
182 | mm_log((1, "bndcheck_all()\n")); | |
76ff75b8 | 183 | for(idx=0; idx<MAXMAL; idx++) |
fe6163bf | 184 | if (malloc_pointers[idx].ptr) |
02d1d628 AMH |
185 | bndcheck(idx); |
186 | } | |
187 | ||
02d1d628 AMH |
188 | void |
189 | myfree_file_line(void *p, char *file, int line) { | |
190 | char *pp = p; | |
191 | int match = 0; | |
192 | int i; | |
193 | ||
fe6163bf | 194 | for(i=0; i<MAXMAL; i++) if (malloc_pointers[i].ptr == p) { |
02d1d628 AMH |
195 | mm_log((1,"myfree_file_line: pointer %i (%s) freed at %s (%i)\n", i, malloc_pointers[i].comm, file, line)); |
196 | bndcheck(i); | |
fe6163bf | 197 | malloc_pointers[i].ptr = NULL; |
02d1d628 AMH |
198 | match++; |
199 | } | |
97c4effc TC |
200 | |
201 | mm_log((1, "myfree_file_line: freeing address %p (real %p)\n", pp, pp-UNDRRNVAL)); | |
02d1d628 AMH |
202 | |
203 | if (match != 1) { | |
f1ac5027 | 204 | mm_log((1, "myfree_file_line: INCONSISTENT REFCOUNT %d at %s (%i)\n", match, file, line)); |
aea697ad | 205 | fprintf(stderr, "myfree_file_line: INCONSISTENT REFCOUNT %d at %s (%i)\n", match, file, line); |
a73aeb5f | 206 | exit(255); |
02d1d628 AMH |
207 | } |
208 | ||
02d1d628 AMH |
209 | |
210 | free(pp-UNDRRNVAL); | |
211 | } | |
212 | ||
e310e5f9 TC |
213 | void |
214 | (myfree)(void *block) { | |
215 | myfree_file_line(block, "unknown", 0); | |
216 | } | |
217 | ||
02d1d628 AMH |
218 | #else |
219 | ||
220 | #define malloc_comm(a,b) (mymalloc(a)) | |
221 | ||
222 | void | |
223 | malloc_state() { | |
02d1d628 AMH |
224 | } |
225 | ||
226 | void* | |
227 | mymalloc(int size) { | |
228 | void *buf; | |
229 | ||
a659442a TC |
230 | if (size < 0) { |
231 | fprintf(stderr, "Attempt to allocate size %d\n", size); | |
232 | exit(3); | |
233 | } | |
234 | ||
a743c0a6 | 235 | if ( (buf = malloc(size)) == NULL ) { |
faa9b3e7 | 236 | mm_log((1, "mymalloc: unable to malloc %d\n", size)); |
cc6483e0 | 237 | fprintf(stderr,"Unable to malloc %d.\n", size); exit(3); |
02d1d628 | 238 | } |
f1ac5027 | 239 | mm_log((1, "mymalloc(size %d) -> %p\n", size, buf)); |
02d1d628 AMH |
240 | return buf; |
241 | } | |
242 | ||
e310e5f9 TC |
243 | void * |
244 | mymalloc_file_line(size_t size, char *file, int line) { | |
245 | return mymalloc(size); | |
246 | } | |
247 | ||
02d1d628 AMH |
248 | void |
249 | myfree(void *p) { | |
dd55acc8 | 250 | mm_log((1, "myfree(p %p)\n", p)); |
02d1d628 AMH |
251 | free(p); |
252 | } | |
253 | ||
e310e5f9 TC |
254 | void |
255 | myfree_file_line(void *p, char *file, int line) { | |
256 | myfree(p); | |
257 | } | |
258 | ||
faa9b3e7 TC |
259 | void * |
260 | myrealloc(void *block, size_t size) { | |
261 | void *result; | |
262 | ||
263 | mm_log((1, "myrealloc(block %p, size %u)\n", block, size)); | |
264 | if ((result = realloc(block, size)) == NULL) { | |
265 | mm_log((1, "myrealloc: out of memory\n")); | |
266 | fprintf(stderr, "Out of memory.\n"); | |
267 | exit(3); | |
268 | } | |
269 | return result; | |
270 | } | |
271 | ||
e310e5f9 TC |
272 | void * |
273 | myrealloc_file_line(void *block, size_t newsize, char *file, int size) { | |
274 | return myrealloc(block, newsize); | |
275 | } | |
276 | ||
02d1d628 AMH |
277 | #endif /* IMAGER_MALLOC_DEBUG */ |
278 | ||
279 | ||
280 | ||
281 | ||
8047cbb5 AMH |
282 | /* memory pool implementation */ |
283 | ||
284 | void | |
285 | i_mempool_init(i_mempool *mp) { | |
286 | mp->alloc = 10; | |
287 | mp->used = 0; | |
288 | mp->p = mymalloc(sizeof(void*)*mp->alloc); | |
289 | } | |
290 | ||
291 | void | |
292 | i_mempool_extend(i_mempool *mp) { | |
293 | mp->p = myrealloc(mp->p, mp->alloc * 2); | |
294 | mp->alloc *=2; | |
295 | } | |
296 | ||
297 | void * | |
298 | i_mempool_alloc(i_mempool *mp, size_t size) { | |
299 | if (mp->used == mp->alloc) i_mempool_extend(mp); | |
300 | mp->p[mp->used] = mymalloc(size); | |
301 | mp->used++; | |
302 | return mp->p[mp->used-1]; | |
303 | } | |
304 | ||
305 | ||
306 | void | |
307 | i_mempool_destroy(i_mempool *mp) { | |
308 | unsigned int i; | |
309 | for(i=0; i<mp->used; i++) myfree(mp->p[i]); | |
310 | myfree(mp->p); | |
311 | } | |
312 | ||
02d1d628 AMH |
313 | |
314 | ||
5473b91d | 315 | /* Should these really be here? */ |
02d1d628 AMH |
316 | |
317 | #undef min | |
318 | #undef max | |
319 | ||
320 | int | |
b33c08f8 | 321 | i_min(int a,int b) { |
02d1d628 AMH |
322 | if (a<b) return a; else return b; |
323 | } | |
324 | ||
325 | int | |
b33c08f8 | 326 | i_max(int a,int b) { |
02d1d628 AMH |
327 | if (a>b) return a; else return b; |
328 | } | |
329 | ||
4f68b48f TC |
330 | |
331 | struct utf8_size { | |
332 | int mask, expect; | |
333 | int size; | |
334 | }; | |
335 | ||
336 | struct utf8_size utf8_sizes[] = | |
337 | { | |
338 | { 0x80, 0x00, 1 }, | |
339 | { 0xE0, 0xC0, 2 }, | |
340 | { 0xF0, 0xE0, 3 }, | |
341 | { 0xF8, 0xF0, 4 }, | |
342 | }; | |
343 | ||
344 | /* | |
345 | =item utf8_advance(char **p, int *len) | |
346 | ||
347 | Retreive a UTF8 character from the stream. | |
348 | ||
349 | Modifies *p and *len to indicate the consumed characters. | |
350 | ||
351 | This doesn't support the extended UTF8 encoding used by later versions | |
352 | of Perl. | |
353 | ||
354 | =cut | |
355 | */ | |
356 | ||
357 | unsigned long i_utf8_advance(char const **p, int *len) { | |
358 | unsigned char c; | |
359 | int i, ci, clen = 0; | |
360 | unsigned char codes[3]; | |
361 | if (*len == 0) | |
362 | return ~0UL; | |
363 | c = *(*p)++; --*len; | |
364 | ||
365 | for (i = 0; i < sizeof(utf8_sizes)/sizeof(*utf8_sizes); ++i) { | |
366 | if ((c & utf8_sizes[i].mask) == utf8_sizes[i].expect) { | |
367 | clen = utf8_sizes[i].size; | |
368 | } | |
369 | } | |
370 | if (clen == 0 || *len < clen-1) { | |
371 | --*p; ++*len; | |
372 | return ~0UL; | |
373 | } | |
374 | ||
375 | /* check that each character is well formed */ | |
376 | i = 1; | |
377 | ci = 0; | |
378 | while (i < clen) { | |
379 | if (((*p)[ci] & 0xC0) != 0x80) { | |
380 | --*p; ++*len; | |
381 | return ~0UL; | |
382 | } | |
383 | codes[ci] = (*p)[ci]; | |
384 | ++ci; ++i; | |
385 | } | |
386 | *p += clen-1; *len -= clen-1; | |
387 | if (c & 0x80) { | |
388 | if ((c & 0xE0) == 0xC0) { | |
389 | return ((c & 0x1F) << 6) + (codes[0] & 0x3F); | |
390 | } | |
391 | else if ((c & 0xF0) == 0xE0) { | |
392 | return ((c & 0x0F) << 12) | ((codes[0] & 0x3F) << 6) | (codes[1] & 0x3f); | |
393 | } | |
394 | else if ((c & 0xF8) == 0xF0) { | |
395 | return ((c & 0x07) << 18) | ((codes[0] & 0x3F) << 12) | |
396 | | ((codes[1] & 0x3F) << 6) | (codes[2] & 0x3F); | |
397 | } | |
398 | else { | |
399 | *p -= clen; *len += clen; | |
400 | return ~0UL; | |
401 | } | |
402 | } | |
403 | else { | |
404 | return c; | |
405 | } | |
406 | } | |
407 |