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