]> git.imager.perl.org - imager.git/blob - io.c
correct cast
[imager.git] / io.c
1 #include "imager.h"
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
13 #define MAXMAL 102400
14 #define MAXDESC 65
15
16 #define UNDRRNVAL 10
17 #define OVERRNVAL 10
18
19 #define PADBYTE 0xaa
20
21
22 static int malloc_need_init = 1;
23
24 typedef struct {
25   void* ptr;
26   size_t size;
27   char comm[MAXDESC];
28 } malloc_entry;
29
30 malloc_entry malloc_pointers[MAXMAL];
31
32
33
34
35 /* Utility functions */
36
37
38 static
39 void
40 malloc_init(void) {
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
75 void
76 malloc_state(void) {
77   int i, total = 0;
78
79   i_clear_error();
80   mm_log((0,"malloc_state()\n"));
81   bndcheck_all();
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;
85   }
86   if (total == 0) mm_log((0,"No memory currently used!\n"))
87                     else mm_log((0,"total: %d\n",total));
88 }
89
90
91
92 void*
93 mymalloc_file_line(size_t size, char* file, int line) {
94   char *buf;
95   int i;
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);
103   }
104
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);
108   }
109   
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;
113 }
114
115 void *
116 (mymalloc)(int size) {
117   return mymalloc_file_line(size, "unknown", 0);
118 }
119
120 void*
121 myrealloc_file_line(void *ptr, size_t newsize, char* file, int line) {
122   char *buf;
123   int i;
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);
131   }
132   
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   }
138
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   
144   if ( (buf = realloc(((char *)ptr)-UNDRRNVAL, UNDRRNVAL+OVERRNVAL+newsize)) == NULL ) {
145     mm_log((1,"Unable to reallocate %i bytes at %p for %s (%i)\n", newsize, ptr, file, line));
146     exit(3); 
147   }
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;
152 }
153
154 void *
155 (myrealloc)(void *ptr, size_t newsize) {
156   return myrealloc_file_line(ptr, newsize, "unknown", 0);
157 }
158
159 static
160 void
161 bndcheck(int idx) {
162   int i;
163   size_t s = malloc_pointers[idx].size;
164   unsigned char *pp = malloc_pointers[idx].ptr;
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++)
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 ));
173   
174      for(i=0;i<OVERRNVAL;i++)
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"));
183   for(idx=0; idx<MAXMAL; idx++)
184     if (malloc_pointers[idx].ptr)
185       bndcheck(idx);
186 }
187
188 void
189 myfree_file_line(void *p, char *file, int line) {
190   char  *pp = p;
191   int match = 0;
192   int i;
193
194   if (p == NULL)
195     return;
196   
197   for(i=0; i<MAXMAL; i++) if (malloc_pointers[i].ptr == p) {
198     mm_log((1,"myfree_file_line: pointer %i (%s) freed at %s (%i)\n", i, malloc_pointers[i].comm, file, line));
199     bndcheck(i);
200     malloc_pointers[i].ptr = NULL;
201     match++;
202   }
203
204   mm_log((1, "myfree_file_line: freeing address %p (real %p)\n", pp, pp-UNDRRNVAL));
205   
206   if (match != 1) {
207     mm_log((1, "myfree_file_line: INCONSISTENT REFCOUNT %d at %s (%i)\n", match, file, line));
208     fprintf(stderr, "myfree_file_line: INCONSISTENT REFCOUNT %d at %s (%i)\n", match, file, line);
209                 exit(255);
210   }
211   
212   
213   free(pp-UNDRRNVAL);
214 }
215
216 void
217 (myfree)(void *block) {
218   myfree_file_line(block, "unknown", 0);
219 }
220
221 #else 
222
223 #define malloc_comm(a,b) (mymalloc(a))
224
225 void
226 malloc_state() {
227 }
228
229 void*
230 mymalloc(int size) {
231   void *buf;
232
233   if (size < 0) {
234     fprintf(stderr, "Attempt to allocate size %d\n", size);
235     exit(3);
236   }
237
238   if ( (buf = malloc(size)) == NULL ) {
239     mm_log((1, "mymalloc: unable to malloc %d\n", size));
240     fprintf(stderr,"Unable to malloc %d.\n", size); exit(3);
241   }
242   mm_log((1, "mymalloc(size %d) -> %p\n", size, buf));
243   return buf;
244 }
245
246 void *
247 mymalloc_file_line(size_t size, char *file, int line) {
248   return mymalloc(size);
249 }
250
251 void
252 myfree(void *p) {
253   mm_log((1, "myfree(p %p)\n", p));
254   free(p);
255 }
256
257 void
258 myfree_file_line(void *p, char *file, int line) {
259   myfree(p);
260 }
261
262 void *
263 myrealloc(void *block, size_t size) {
264   void *result;
265
266   mm_log((1, "myrealloc(block %p, size %u)\n", block, size));
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
275 void *
276 myrealloc_file_line(void *block, size_t newsize, char *file, int size) {
277   return myrealloc(block, newsize);
278 }
279
280 #endif /* IMAGER_MALLOC_DEBUG */
281
282
283
284
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
316
317
318 /* Should these really be here? */
319
320 #undef min
321 #undef max
322
323 int
324 i_min(int a,int b) {
325   if (a<b) return a; else return b;
326 }
327
328 int
329 i_max(int a,int b) {
330   if (a>b) return a; else return b;
331 }
332
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 /*
348 =item utf8_advance(char **p, int *len)
349
350 Retreive a UTF8 character from the stream.
351
352 Modifies *p and *len to indicate the consumed characters.
353
354 This doesn't support the extended UTF8 encoding used by later versions
355 of Perl.
356
357 This doesn't check that the UTF8 charecter is using the shortest
358 possible representation.
359
360 =cut
361 */
362
363 unsigned long 
364 i_utf8_advance(char const **p, int *len) {
365   unsigned char c;
366   int i, ci, clen = 0;
367   unsigned char codes[3];
368   if (*len == 0)
369     return ~0UL;
370   c = *(*p)++; --*len;
371
372   for (i = 0; i < sizeof(utf8_sizes)/sizeof(*utf8_sizes); ++i) {
373     if ((c & utf8_sizes[i].mask) == utf8_sizes[i].expect) {
374       clen = utf8_sizes[i].size;
375       break;
376     }
377   }
378   if (clen == 0 || *len < clen-1) {
379     --*p; ++*len;
380     return ~0UL;
381   }
382
383   /* check that each character is well formed */
384   i = 1;
385   ci = 0;
386   while (i < clen) {
387     if (((*p)[ci] & 0xC0) != 0x80) {
388       --*p; ++*len;
389       return ~0UL;
390     }
391     codes[ci] = (*p)[ci];
392     ++ci; ++i;
393   }
394   *p += clen-1; *len -= clen-1;
395   if (c & 0x80) {
396     if ((c & 0xE0) == 0xC0) {
397       return ((c & 0x1F) << 6) + (codes[0] & 0x3F);
398     }
399     else if ((c & 0xF0) == 0xE0) {
400       return ((c & 0x0F) << 12) | ((codes[0] & 0x3F) << 6) | (codes[1] & 0x3f);
401     }
402     else if ((c & 0xF8) == 0xF0) {
403       return ((c & 0x07) << 18) | ((codes[0] & 0x3F) << 12) 
404               | ((codes[1] & 0x3F) << 6) | (codes[2] & 0x3F);
405     }
406     else {
407       *p -= clen; *len += clen;
408       return ~0UL;
409     }
410   }
411   else {
412     return c;
413   }
414 }
415