editor: #undef O after use
[0verkill.git] / error.c
blob5bad5b560767e62c32123bbf8994a1f31951659c
1 /* this code is stolen from the links browser, it was written by Mikulas Patocka */
3 #include <signal.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <stdio.h>
7 #include <stdarg.h>
8 #ifndef WIN32
9 #include <unistd.h>
10 #include "config.h"
11 #endif
13 #include "cfg.h"
14 #include "error.h"
15 #include "data.h"
17 struct memory_list {
18 int n;
19 void *p[1];
22 struct list_head {
23 void *next;
24 void *prev;
27 #ifndef HAVE_TYPEOF
29 struct xlist_head {
30 struct xlist_head *next;
31 struct xlist_head *prev;
34 #endif
37 #define del_from_list(x) {((struct list_head *)(x)->next)->prev=(x)->prev; ((struct list_head *)(x)->prev)->next=(x)->next;}
38 #define add_at_pos(p,x) do {(x)->next=(p)->next; (x)->prev=(p); (p)->next=(x); (x)->next->prev=(x);} while(0)
40 #ifdef HAVE_TYPEOF
41 #define foreach(e,l) for ((e)=(l).next; (e)!=(typeof(e))&(l); (e)=(e)->next)
42 #define add_to_list(l,x) add_at_pos((typeof(x))&(l),(x))
43 #else
44 #define foreach(e,l) for ((e)=(l).next; (e)!=(void *)&(l); (e)=(e)->next)
45 #define add_to_list(l,x) add_at_pos((struct xlist_head *)&(l),(struct xlist_head *)(x))
46 #endif
49 /* inline */
51 #ifdef LEAK_DEBUG
53 extern long mem_amount;
54 extern long last_mem_amount;
56 #define ALLOC_MAGIC 0xa110c
57 #define ALLOC_FREE_MAGIC 0xf4ee
58 #define ALLOC_REALLOC_MAGIC 0x4ea110c
60 #ifndef LEAK_DEBUG_LIST
61 struct alloc_header {
62 int magic;
63 int size;
65 #else
66 struct alloc_header {
67 struct alloc_header *next;
68 struct alloc_header *prev;
69 int magic;
70 int size;
71 int line;
72 char *file;
73 char *comment;
75 #endif
77 #define L_D_S ((sizeof(struct alloc_header) + 7) & ~7)
79 #endif
81 /*-----------------------------------------------------------------------------*/
83 void do_not_optimize_here(void *p)
85 p=p;
86 /* stop GCC optimization - avoid bugs in it */
89 #ifdef LEAK_DEBUG
90 long mem_amount = 0;
91 long last_mem_amount = -1;
92 #ifdef LEAK_DEBUG_LIST
93 struct list_head memory_list = { &memory_list, &memory_list };
94 #endif
95 #endif
97 static inline void force_dump(void)
99 fprintf(stderr, "\n\033[1m%s\033[0m\n", "Forcing core dump");
100 fflush(stderr);
101 raise(SIGSEGV);
104 void check_memory_leaks(void)
106 #ifdef LEAK_DEBUG
107 if (mem_amount) {
108 fprintf(stderr, "\n\033[1mMemory leak by %ld bytes\033[0m\n", mem_amount);
109 #ifdef LEAK_DEBUG_LIST
110 fprintf(stderr, "\nList of blocks: ");
112 int r = 0;
113 struct alloc_header *ah;
114 foreach (ah, memory_list) {
115 fprintf(stderr, "%s%p:%d @ %s:%d", r ? ", ": "", (char *)ah + L_D_S, ah->size, ah->file, ah->line), r = 1;
116 if (ah->comment) fprintf(stderr, ":\"%s\"", ah->comment);
118 fprintf(stderr, "\n");
120 #endif
121 force_dump();
123 #endif
126 void er(int b, char *m, va_list l)
128 if (b) fprintf(stderr, "%c", (char)7);
129 vfprintf(stderr, m, l);
130 fprintf(stderr, "\n");
131 sleep(1);
134 #ifndef WIN32
135 void error(char *m, ...)
137 va_list l;
138 va_start(l, m);
139 er(1, m, l);
141 #endif
143 int errline;
144 char *errfile;
146 char errbuf[4096];
148 void int_error(char *m, ...)
150 va_list l;
151 va_start(l, m);
152 snprintf(errbuf, sizeof(errbuf), "\033[1mINTERNAL ERROR\033[0m at %s:%d: ", errfile, errline);
153 strcat(errbuf, m);
154 er(1, errbuf, l);
155 force_dump();
158 void debug_msg(char *m, ...)
160 va_list l;
161 va_start(l, m);
162 snprintf(errbuf, sizeof(errbuf), "DEBUG MESSAGE at %s:%d: ", errfile, errline);
163 strcat(errbuf, m);
164 er(0, errbuf, l);
167 #ifdef LEAK_DEBUG
169 void *debug_mem_alloc(char *file, int line, size_t size)
171 void *p;
172 #ifdef LEAK_DEBUG
173 struct alloc_header *ah;
174 #endif
175 if (!size) return DUMMY;
176 #ifdef LEAK_DEBUG
177 mem_amount += size;
178 size += L_D_S;
179 #endif
180 if (!(p = malloc(size))) {
181 error("ERROR: out of memory (malloc returned NULL)\n");
182 return NULL;
184 #ifdef LEAK_DEBUG
185 ah = p;
186 p = (char *)p + L_D_S;
187 ah->size = size - L_D_S;
188 ah->magic = ALLOC_MAGIC;
189 #ifdef LEAK_DEBUG_LIST
190 ah->file = file;
191 ah->line = line;
192 ah->comment = NULL;
193 add_to_list(memory_list, ah);
194 #endif
195 #endif
196 memset(p, 'A', size - L_D_S);
197 return p;
200 void *debug_mem_calloc(char *file, int line, size_t size)
202 void *p;
203 #ifdef LEAK_DEBUG
204 struct alloc_header *ah;
205 #endif
206 if (!size) return DUMMY;
207 #ifdef LEAK_DEBUG
208 mem_amount += size;
209 size += L_D_S;
210 #endif
211 if (!(p = x_calloc(size))) {
212 error("ERROR: out of memory (calloc returned NULL)\n");
213 return NULL;
215 #ifdef LEAK_DEBUG
216 ah = p;
217 p = (char *)p + L_D_S;
218 ah->size = size - L_D_S;
219 ah->magic = ALLOC_MAGIC;
220 #ifdef LEAK_DEBUG_LIST
221 ah->file = file;
222 ah->line = line;
223 ah->comment = NULL;
224 add_to_list(memory_list, ah);
225 #endif
226 #endif
227 return p;
230 void debug_mem_free(char *file, int line, void *p)
232 #ifdef LEAK_DEBUG
233 struct alloc_header *ah;
234 #endif
235 if (p == DUMMY) return;
236 if (!p) {
237 errfile = file, errline = line, int_error("mem_free(NULL)");
238 return;
240 #ifdef LEAK_DEBUG
241 p = (char *)p - L_D_S;
242 ah = p;
243 if (ah->magic != ALLOC_MAGIC) {
244 errfile = file, errline = line, int_error("mem_free: magic doesn't match: %08x", ah->magic);
245 return;
247 ah->magic = ALLOC_FREE_MAGIC;
248 #ifdef LEAK_DEBUG_LIST
249 del_from_list(ah);
250 if (ah->comment) free(ah->comment);
251 #endif
252 mem_amount -= ah->size;
253 #endif
254 free(p);
257 void *debug_mem_realloc(char *file, int line, void *p, size_t size)
259 #ifdef LEAK_DEBUG
260 struct alloc_header *ah;
261 #endif
262 if (p == DUMMY) return debug_mem_alloc(file, line, size);
263 if (!p) {
264 errfile = file, errline = line, int_error("mem_realloc(NULL, %d)", size);
265 return NULL;
267 if (!size) {
268 debug_mem_free(file, line, p);
269 return DUMMY;
271 #ifdef LEAK_DEBUG
272 p = (char *)p - L_D_S;
273 ah = p;
274 if (ah->magic != ALLOC_MAGIC) {
275 errfile = file, errline = line, int_error("mem_realloc: magic doesn't match: %08x", ah->magic);
276 return NULL;
278 ah->magic = ALLOC_REALLOC_MAGIC;
279 #endif
280 if (!(p = realloc(p, size + L_D_S))) {
281 error("ERROR: out of memory (realloc returned NULL)\n");
282 return NULL;
284 #ifdef LEAK_DEBUG
285 ah = p;
286 mem_amount += size - ah->size;
287 ah->size = size;
288 ah->magic = ALLOC_MAGIC;
289 #ifdef LEAK_DEBUG_LIST
290 ah->prev->next = ah;
291 ah->next->prev = ah;
292 #endif
293 #endif
294 return (char *)p + L_D_S;
297 void set_mem_comment(void *p, char *c, int l)
299 #ifdef LEAK_DEBUG_LIST
300 struct alloc_header *ah = (struct alloc_header *)((char *)p - L_D_S);
301 if (ah->comment) free(ah->comment);
302 if ((ah->comment = malloc(l + 1))) memcpy(ah->comment, c, l), ah->comment[l] = 0;
303 #endif
306 #endif