forgot to add the chkalloc files
[dos_imgv] / src / chkalloc.c
1 #ifdef CHECK_ALLOC
2
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include "chkalloc.h"
7 #include "util.h"
8
9 #define OFFSET  512
10
11 struct allocation {
12         char *ptr;
13         char *file;
14         int fullsz, sz;
15         int lineno;
16         struct allocation *next;
17 };
18
19 static FILE *logfile;
20 static struct allocation *alist, *atail;
21
22 static void init_once(void)
23 {
24         static int init_once_done;
25         if(!init_once_done) {
26                 init_once_done = 1;
27                 remove("chk.log");
28         }
29 }
30
31 static FILE *openlog(void)
32 {
33         if(logfile) return logfile;
34         return (logfile = fopen("chk.log", "a"));
35 }
36
37 static void closelog(void)
38 {
39         fclose(logfile);
40         logfile = 0;
41 }
42
43 static void mark_alloc(struct allocation *a)
44 {
45         uintptr_t *left, *right, *end;
46
47         left = (uintptr_t*)(a + 1);
48         right = (uintptr_t*)((char*)a + a->fullsz) - 1;
49         end = (uintptr_t*)(a->ptr + a->sz);
50
51         while(left + 1 < (void*)a->ptr) {
52                 *left = (uintptr_t)left;
53                 left++;
54         }
55         while(right >= end) {
56                 *right = (uintptr_t)right;
57                 right--;
58         }
59 }
60
61 static int check_alloc(struct allocation *a, const char *reason)
62 {
63         int i;
64         uintptr_t *left = (uintptr_t*)(a + 1);
65         uintptr_t *right = (uintptr_t*)((char*)a + a->fullsz) - 1;
66         void *end = a->ptr + a->sz;
67         int trash_left = 0, trash_right = 0;
68         char *last_trash_left = 0, *first_trash_right = 0;
69         char *first_trash_left = 0, *last_trash_right = 0;
70
71         init_once();
72         if(!openlog()) return -1;
73
74         while(left + 1 < (void*)a->ptr) {
75                 if(*left != (uintptr_t)left) {
76                         fprintf(logfile, "@%p: %p\n", left, (void*)*left);
77                 }
78                 for(i=0; i<sizeof *left; i++) {
79                         int s = i << 3;
80                         if(((*left >> s) & 0xff) != (((uintptr_t)left >> s) & 0xff)) {
81                                 if(!first_trash_left) first_trash_left = (char*)left;
82                                 trash_left++;
83                                 last_trash_left = (char*)left + i;
84                         }
85                 }
86                 left++;
87         }
88         while(right >= end) {
89                 if(*right != (uintptr_t)right) {
90                         fprintf(logfile, "@%p: %p\n", right, (void*)*right);
91                 }
92                 for(i=0; i<sizeof *right; i++) {
93                         int s = i << 3;
94                         if(((*right >> s) & 0xff) != (((uintptr_t)right >> s) & 0xff)) {
95                                 if(!last_trash_right) last_trash_right = (char*)right;
96                                 trash_right++;
97                                 first_trash_right = (char*)right + i;
98                         }
99                 }
100                 right--;
101         }
102
103         if(!(trash_left | trash_right)) return 0;
104
105         fprintf(logfile, "corrupted memory allocated from: %s:%d\n", a->file, a->lineno);
106         if(trash_left) {
107                 fprintf(logfile, " %d bytes at offset %d before start (%p)\n",
108                                 (int)(last_trash_left - first_trash_left),
109                                 (int)(a->ptr - last_trash_left), a->ptr);
110         }
111         if(trash_right) {
112                 fprintf(logfile, " %d bytes at offset %d after end (%p)\n",
113                                 (int)(last_trash_right - first_trash_right),
114                                 (int)(first_trash_right - end), end);
115         }
116         fprintf(logfile, " check due to %s\n", reason);
117         closelog();
118         return -1;
119 }
120
121 void chk_check(void)
122 {
123         struct allocation *anode = alist;
124         while(anode) {
125                 check_alloc(anode, "explicit check call");
126                 anode = anode->next;
127         }
128 }
129
130 void *chk_malloc_impl(int sz, char *file, int line)
131 {
132         int fullsz;
133         struct allocation *a;
134
135         init_once();
136
137         fullsz = sz + OFFSET * 2;
138         if(!(a = malloc(fullsz))) {
139                 return 0;
140         }
141
142         a->ptr = (char*)a + OFFSET;
143         a->file = file;
144         a->lineno = line;
145         a->fullsz = fullsz;
146         a->sz = sz;
147         a->next = 0;
148
149         if(alist) {
150                 atail->next = a;
151                 atail = a;
152         } else {
153                 alist = atail = a;
154         }
155
156         mark_alloc(a);
157
158         if(openlog()) {
159                 fprintf(logfile, "alloc(%d) from %s:%d\n", sz, a->file, a->lineno);
160                 closelog();
161         }
162         return a->ptr;
163 }
164
165 void *chk_realloc_impl(void *ptr, int sz, char *file, int line)
166 {
167         int fullsz;
168         struct allocation *newptr;
169         struct allocation *a = (struct allocation*)((char*)ptr - OFFSET);
170         struct allocation *prev, dummy;
171
172         init_once();
173         if(ptr) {
174                 check_alloc(a, "realloc");
175         }
176
177         fullsz = sz + OFFSET * 2;
178         if(!(newptr = realloc(a, fullsz))) {
179                 return 0;
180         }
181
182         dummy.next = alist;
183         prev = &dummy;
184         while(prev->next) {
185                 if(prev->next == a) {
186                         prev->next = newptr;
187                         break;
188                 }
189                 prev = prev->next;
190         }
191         alist = dummy.next;
192
193         a = newptr;
194         a->ptr = (char*)a + OFFSET;
195         a->sz = sz;
196         a->fullsz = fullsz;
197         a->file = file;
198         a->lineno = line;
199
200         mark_alloc(a);
201
202         if(openlog()) {
203                 fprintf(logfile, "realloc(%d) from %s:%d\n", sz, a->file, a->lineno);
204                 closelog();
205         }
206         return a->ptr;
207 }
208
209 void chk_free(void *p)
210 {
211         struct allocation dummy, *prev, *a;
212
213         init_once();
214
215         if(!p) return;
216
217         a = (struct allocation*)((char*)p - OFFSET);
218         if(openlog()) {
219                 fprintf(logfile, "free() %d allocated from %s:%d\n", a->sz, a->file, a->lineno);
220                 closelog();
221         }
222
223         dummy.next = alist;
224         prev = &dummy;
225         while(prev->next) {
226                 if(prev->next->ptr == p) {
227                         a = prev->next;
228                         prev->next = a->next;
229
230                         check_alloc(a, "free");
231                         free(a);
232                         break;
233                 }
234                 prev = prev->next;
235         }
236         alist = dummy.next;
237 }
238
239 #endif  /* CHECK_ALLOC */