Fix crash after recursive aliasing
[capablanca.git] / lasker-2.2.3 / src / malloc.c
1 /*
2    Copyright (C) Andrew Tridgell 2002
3    
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 2 of the License, or
7    (at your option) any later version.
8    
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13    
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, write to the Free Software
16    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18
19 /*
20   a malloc wrapper library for the dynamically loaded part of
21   chessd. This is used both as a malloc checker library and to prevent
22   some bad interactions between the dl library and malloc
23 */
24
25
26 #include "includes.h"
27 #undef free
28 #undef malloc
29
30 #define MAGIC1 0x28021967
31 #define MAGIC2 0x26011966
32
33 struct malloc_list {
34         void *ptr;
35         struct malloc_list *next;
36         struct malloc_list *prev;
37 };
38
39 static struct malloc_list *mlist;
40 static int m_total;
41
42 struct malloc_header {
43         struct malloc_list *m;
44         unsigned size;
45         unsigned magic;
46 };
47
48 /*
49   a magic-value protected malloc wrapper, 
50   which can be globally freed using a single call
51 */
52 void *m_malloc(size_t size)
53 {
54         void *ptr;
55         struct malloc_list *m;
56         struct malloc_header *h;
57
58         if (size == 0) return NULL;
59
60         ptr = malloc(size+sizeof(struct malloc_header));
61
62         if (!ptr) return NULL;
63
64         m = malloc(sizeof(*m));
65
66 #if MALLOC_DEBUG
67         fprintf(stderr,"malloc %p   %u\n", ptr, size);
68         fprintf(stderr,"malloc %p\n", m);
69 #endif
70
71         if (!m) {
72                 free(ptr);
73                 return NULL;
74         }
75
76         m->ptr = ptr;
77         m->next = mlist;
78         m->prev = NULL;
79         if (mlist) {
80                 mlist->prev = m;
81         }
82         mlist = m;
83
84         m_total++;
85
86         memset(ptr, 0, size+sizeof(struct malloc_header));
87
88         h = ptr;
89         h->size = size;
90         h->magic = MAGIC1;
91         h->m = m;
92
93         return (void *)(h+1);
94 }
95
96 /*
97   determine the size of a malloced region
98 */
99 static size_t m_malloc_size(void *ptr)
100 {
101         struct malloc_header *h;
102         if (!ptr) return 0;
103
104         h = (struct malloc_header *)ptr;
105         h--;
106
107         return h->size;
108 }
109
110 /*
111   check that a pointer is OK
112 */
113 void m_malloc_check(void *ptr)
114 {
115         struct malloc_header *h;
116
117         if (!ptr) return;
118
119         h = (struct malloc_header *)ptr;
120         h--;
121
122         if (h->magic != MAGIC1) {
123                 d_printf("malloc corruption ptr=%p v1=%x size=%d\n", 
124                          ptr, h->magic, h->size);
125         }
126 }
127
128 /*
129   a paranoid free() function that checks for simple corruption
130 */
131 int m_free(void *ptr)
132 {
133         struct malloc_header *h;
134         struct malloc_list *m;
135
136         if (!ptr) return 0;
137
138         h = (struct malloc_header *)ptr;
139         h--;
140
141         if (h->magic != MAGIC1) {
142                 d_printf("malloc corruption ptr=%p v1=%x size=%d\n", 
143                         ptr, h->magic, h->size);
144                 return -1;
145         }
146
147         m = h->m;
148         if (!m || m->ptr != h) {
149                 d_printf("malloc list corruption!\n");
150         }
151         if (m->next) {
152                 m->next->prev = m->prev;
153         }
154         if (m->prev) {
155                 m->prev->next = m->next;
156         }
157         if (m == mlist) {
158                 mlist = m->next;
159         }
160
161         m_total--;
162
163 #if MALLOC_DEBUG
164         fprintf(stderr,"free   %p   %u\n", h, h->size);
165         fprintf(stderr,"free   %p\n", m);
166 #endif
167
168         memset(ptr, 'Z', h->size); /* paranoia */
169         memset(m, 0, sizeof(*m));
170         free(m);
171         memset(h, 0, sizeof(*h));
172         free(h);
173         return 0;
174 }
175
176 /*
177   check all allocated memory
178 */
179 void m_check_all(void)
180 {
181         struct malloc_list *m;
182         for (m=mlist; m; m=m->next) {
183                 m_malloc_check(m->ptr + sizeof(struct malloc_header));
184         }
185 }
186
187
188 /*
189   free all allocated memory
190 */
191 void m_free_all(void)
192 {
193         struct malloc_list *m, *next;
194         d_printf("Freeing %d chunks\n", m_total);
195         for (m=mlist; m; m=next) {
196                 next = m->next;
197                 m_total--;
198
199 #if MALLOC_DEBUG
200                 fprintf(stderr,"free   %p\n", m->ptr);
201                 fprintf(stderr,"free   %p\n", m);
202 #endif
203                 free(m->ptr);
204                 free(m);
205         }
206         mlist = NULL;
207 }
208
209 /* a calloc wrapper */
210 void *m_calloc(size_t n, size_t size)
211 {
212         void *ptr;
213         ptr = m_malloc(n*size);
214         if (ptr) memset(ptr, 0, n*size);
215         return ptr;
216 }
217
218 /* strdup wrapper */
219 char *m_strdup(const char *s)
220 {
221         int len = strlen(s);
222         char *ret;
223         ret = m_malloc(len+1);
224         memcpy(ret, s, len+1);
225         return ret;
226 }
227
228 /* strndup wrapper */
229 char *m_strndup(const char *s, size_t n)
230 {
231         int len = strnlen(s, n);
232         char *ret;
233         ret = m_malloc(len+1);
234         memcpy(ret, s, len);
235         ret[len] = 0;
236         return ret;
237 }
238
239 /* a free() call that zeros the pointer to prevent re-use */
240 void m_safe_free(void **ptr, const char *file, unsigned line)
241 {
242         if (!*ptr) {
243                 d_printf("NULL free at %s(%u)!\n", file, line);
244                 return;
245         }
246         if (m_free(*ptr) != 0) {
247                 d_printf("bad free at %s(%u)!\n", file, line);
248         }
249         (*ptr) = NULL;
250 }
251
252
253 /* a vasprintf wrapper */
254 int m_vasprintf(char **strp, const char *fmt, va_list ap)
255 {
256         int n;
257
258         (*strp) = NULL;
259
260         n = vsnprintf(NULL, 0, fmt, ap);
261         if (n == 0) return 0;
262
263         (*strp) = m_malloc(n+1);
264         n = vsnprintf(*strp, n+1, fmt, ap);
265         
266         return n;
267 }
268
269 /* a asprintf wrapper */
270 int m_asprintf(char **strp, const char *fmt, ...)
271 {
272         int n;
273         va_list ap;
274
275         va_start(ap, fmt);
276         n = m_vasprintf(strp, fmt, ap);
277         va_end(ap);
278
279         return n;
280 }
281
282 /* a realloc wrapper */
283 void *m_realloc(void *ptr, size_t size)
284 {
285         void *ret;
286         size_t msize;
287
288         if (!ptr) {
289                 return m_malloc(size);
290         }
291
292         if (size == 0) {
293                 m_safe_free(&ptr, __FILE__, __LINE__);
294                 return NULL;
295         }
296
297         ret = m_malloc(size);
298
299         msize = m_malloc_size(ptr);
300         memcpy(ret, ptr, size<msize?size:msize);
301         m_safe_free(&ptr, __FILE__, __LINE__);
302         return ret;
303 }