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