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