And the rest! ;) --aphex
[blender-staging.git] / intern / guardedalloc / intern / mallocn.c
1 /**
2  * $Id$
3  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version. The Blender
9  * Foundation also sells licenses for use in proprietary software under
10  * the Blender License.  See http://www.blender.org/BL/ for information
11  * about this.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software Foundation,
20  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21  *
22  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
23  * All rights reserved.
24  *
25  * The Original Code is: all of this file.
26  *
27  * Contributor(s): none yet.
28  *
29  * ***** END GPL/BL DUAL LICENSE BLOCK *****
30  */
31
32 /**
33
34  * $Id$
35  * Copyright (C) 2001 NaN Technologies B.V.
36  * Guarded memory allocation, and boundary-write detection.
37  */
38
39 #include <stdlib.h>
40
41 #ifdef HAVE_CONFIG_H
42 #include <config.h>
43 #endif
44
45 #include "MEM_guardedalloc.h"
46
47 /* --------------------------------------------------------------------- */
48 /* Data definition                                                       */
49 /* --------------------------------------------------------------------- */
50 /* all memory chunks are put in linked lists */
51 typedef struct localLink
52 {
53         struct localLink *next,*prev;
54 } localLink;
55
56 typedef struct localListBase 
57 {
58         void *first, *last;
59 } localListBase;
60
61 typedef struct MemHead {
62         int tag1;
63         int len;
64         struct MemHead *next,*prev;
65         char * name;
66         char * nextname;
67         /*  int level; */ /* historical, can be removed, but check alignment issues - zr */
68         int tag2;
69 } MemHead;
70
71 typedef struct MemTail {
72         int tag3, pad;
73 } MemTail;
74
75 /* --------------------------------------------------------------------- */
76 /* local functions                                                       */
77 /* --------------------------------------------------------------------- */
78
79 static void addtail(localListBase *listbase, void *vlink);
80 static void remlink(localListBase *listbase, void *vlink);
81 static void rem_memblock(MemHead *memh);
82 static void MemorY_ErroR(char *block, char *error);
83 static char *check_memlist(MemHead *memh);
84
85 /* --------------------------------------------------------------------- */
86 /* locally used defines                                                  */
87 /* --------------------------------------------------------------------- */
88
89 #if defined( __sgi) || defined (__sun__) || defined (__PPC__) || defined (__APPLE__)
90 #define MAKE_ID(a,b,c,d) ( (int)(a)<<24 | (int)(b)<<16 | (c)<<8 | (d) )
91 #else
92 #define MAKE_ID(a,b,c,d) ( (int)(d)<<24 | (int)(c)<<16 | (b)<<8 | (a) )
93 #endif
94
95 #define MEMTAG1 MAKE_ID('M', 'E', 'M', 'O')
96 #define MEMTAG2 MAKE_ID('R', 'Y', 'B', 'L')
97 #define MEMTAG3 MAKE_ID('O', 'C', 'K', '!')
98 #define MEMFREE MAKE_ID('F', 'R', 'E', 'E')
99
100 #define MEMNEXT(x) ((MemHead *)(((char *) x) - ((char *) & (((MemHead *)0)->next))))
101         
102 /* --------------------------------------------------------------------- */
103 /* vars                                                                  */
104 /* --------------------------------------------------------------------- */
105         
106 int totblock= 0;
107 int mem_in_use= 0;
108
109 static struct localListBase _membase;
110 static struct localListBase *membase = &_membase;
111 static FILE* err_stream = NULL;
112
113 #ifdef malloc
114 #undef malloc
115 #endif
116
117 #ifdef calloc
118 #undef calloc
119 #endif
120
121 #ifdef free
122 #undef free
123 #endif
124
125
126 /* --------------------------------------------------------------------- */
127 /* implementation                                                        */
128 /* --------------------------------------------------------------------- */
129
130 int MEM_check_memory_integrity()
131 {
132         char* err_val = NULL;
133         MemHead* listend;
134         /* check_memlist starts from the front, and runs until it finds
135          * the requested chunk. For this test, that's the last one. */
136         listend = membase->last;
137         
138         err_val = check_memlist(listend);
139
140         return (int)err_val;
141 }
142
143
144 void MEM_set_error_stream(FILE* i)
145 {
146         err_stream = i;
147 }
148
149
150 int MEM_allocN_len(void *vmemh)
151 {
152         if (vmemh) {
153                 MemHead *memh= vmemh;
154         
155                 memh--;
156                 return memh->len;
157         } else
158                 return 0;
159 }
160
161 void *MEM_dupallocN(void *vmemh)
162 {
163         void *newp= NULL;
164         
165         if (vmemh) {
166                 MemHead *memh= vmemh;
167                 memh--;
168
169                 if (memh->len) {
170                         newp= MEM_mallocN(memh->len, "dupli_alloc");
171                         memcpy(newp, vmemh, memh->len);
172                 } else
173                         if (err_stream) fprintf(err_stream, "error: MEM_dupallocN with len==0 %s\n", memh->name);
174         }
175
176         return newp;
177 }
178
179 void *MEM_mallocN(unsigned int len, char *str)
180 {
181         MemHead *memh;
182         MemTail *memt;
183
184         if(sizeof(long)==8)
185                 len = (len + 3 ) & ~3;  /* eenheden van 4 */
186         else 
187                 len = (len + 7 ) & ~7;  /* eenheden van 8 */
188         
189         memh= (MemHead *)malloc(len+sizeof(MemHead)+sizeof(MemTail));
190
191         if(memh!=0) {
192                 memh->tag1 = MEMTAG1;
193                 memh->name = str;
194                 memh->nextname = 0;
195                 memh->len = len;
196 /*              memh->level = 0; */
197                 memh->tag2 = MEMTAG2;
198
199                 memt = (MemTail *)(((char *) memh) + sizeof(MemHead) + len);
200                 memt->tag3 = MEMTAG3;
201
202                 addtail(membase,&memh->next);
203                 if (memh->next) memh->nextname = MEMNEXT(memh->next)->name;
204
205                 totblock++;
206                 mem_in_use += len;
207                 return (++memh);
208         }
209         if (err_stream) fprintf(err_stream, "Malloc returns nill: len=%d in %s\n",len,str);
210         return 0;
211 }
212
213 void *MEM_callocN(unsigned int len, char *str)
214 {
215         MemHead *memh;
216         MemTail *memt;
217
218         if(sizeof(long)==8)
219                 len = (len + 3 ) & ~3;  /* eenheden van 4 */
220         else 
221                 len = (len + 7 ) & ~7;  /* eenheden van 8 */
222
223         memh= (MemHead *)calloc(len+sizeof(MemHead)+sizeof(MemTail),1);
224
225         if(memh!=0) {
226                 memh->tag1 = MEMTAG1;
227                 memh->name = str;
228                 memh->nextname = 0;
229                 memh->len = len;
230 /*              memh->level = 0; */
231                 memh->tag2 = MEMTAG2;
232
233                 memt = (MemTail *)(((char *) memh) + sizeof(MemHead) + len);
234                 memt->tag3 = MEMTAG3;
235
236                 addtail(membase,&memh->next);
237                 if (memh->next) memh->nextname = MEMNEXT(memh->next)->name;
238
239                 totblock++;
240                 mem_in_use += len;
241                 return (++memh);
242         }
243         if (err_stream) fprintf(err_stream, "Calloc returns nill: len=%d in %s\n",len,str);
244         return 0;
245 }
246
247
248 void MEM_printmemlist()
249 {
250         MemHead *membl;
251
252         membl = membase->first;
253         if (membl) membl = MEMNEXT(membl);
254         while(membl) {
255                 if (err_stream) fprintf(err_stream, "%s len: %d %p\n",membl->name,membl->len, membl+1);
256                 if(membl->next)
257                         membl= MEMNEXT(membl->next);
258                 else break;
259         }
260 }
261
262 short MEM_freeN(void *vmemh)            /* anders compileertie niet meer */
263 {
264         short error = 0;
265         MemTail *memt;
266         MemHead *memh= vmemh;
267         char *name;
268
269         if (memh == 0){
270                 MemorY_ErroR("free","attempt to free NULL pointer");
271                 /* if (err_stream) fprintf(err_stream, "%d\n", (memh+4000)->tag1); */
272                 return(-1);
273         }
274
275         if(sizeof(long)==8) {
276                 if (((long) memh) & 0x7) {
277                         MemorY_ErroR("free","attempt to free illegal pointer");
278                         return(-1);
279                 }
280         }
281         else {
282                 if (((long) memh) & 0x3) {
283                         MemorY_ErroR("free","attempt to free illegal pointer");
284                         return(-1);
285                 }
286         }
287         
288         memh--;
289         if(memh->tag1 == MEMFREE && memh->tag2 == MEMFREE) {
290                 MemorY_ErroR(memh->name,"double free");
291                 return(-1);
292         }
293
294         if ((memh->tag1 == MEMTAG1) && (memh->tag2 == MEMTAG2) && ((memh->len & 0x3) == 0)) {
295                 memt = (MemTail *)(((char *) memh) + sizeof(MemHead) + memh->len);
296                 if (memt->tag3 == MEMTAG3){
297                         
298                         memh->tag1 = MEMFREE;
299                         memh->tag2 = MEMFREE;
300                         memt->tag3 = MEMFREE;
301                         /* na tags !!! */
302                         rem_memblock(memh);
303                         
304                         return(0);
305                 }
306                 error = 2;
307                 MemorY_ErroR(memh->name,"end corrupt");
308                 name = check_memlist(memh);
309                 if (name != 0){
310                         if (name != memh->name) MemorY_ErroR(name,"is also corrupt");
311                 }
312         } else{
313                 error = -1;
314                 name = check_memlist(memh);
315                 if (name == 0) MemorY_ErroR("free","pointer not in memlist");
316                 else MemorY_ErroR(name,"error in header");
317         }
318
319         totblock--;
320         /* hier moet een DUMP plaatsvinden */
321
322         return(error);
323 }
324
325 /* --------------------------------------------------------------------- */
326 /* local functions                                                       */
327 /* --------------------------------------------------------------------- */
328
329 static void addtail(localListBase *listbase, void *vlink)
330 {
331         struct localLink *link= vlink;
332
333         if (link == 0) return;
334         if (listbase == 0) return;
335
336         link->next = 0;
337         link->prev = listbase->last;
338
339         if (listbase->last) ((struct localLink *)listbase->last)->next = link;
340         if (listbase->first == 0) listbase->first = link;
341         listbase->last = link;
342 }
343
344 static void remlink(localListBase *listbase, void *vlink)
345 {
346         struct localLink *link= vlink;
347
348         if (link == 0) return;
349         if (listbase == 0) return;
350
351         if (link->next) link->next->prev = link->prev;
352         if (link->prev) link->prev->next = link->next;
353
354         if (listbase->last == link) listbase->last = link->prev;
355         if (listbase->first == link) listbase->first = link->next;
356 }
357
358 static void rem_memblock(MemHead *memh)
359 {
360         remlink(membase,&memh->next);
361         if (memh->prev){
362                 if (memh->next) MEMNEXT(memh->prev)->nextname = MEMNEXT(memh->next)->name;
363                 else MEMNEXT(memh->prev)->nextname = 0;
364         }
365
366         totblock--;
367         mem_in_use -= memh->len;
368         free(memh);
369 }
370
371 static void MemorY_ErroR(char *block, char *error)
372 {
373         if (err_stream) fprintf(err_stream,"Memoryblock %s: %s\n",block,error);
374 }
375
376 static char *check_memlist(MemHead *memh)
377 {
378         MemHead *forw,*back,*forwok,*backok;
379         char *name;
380
381         forw = membase->first;
382         if (forw) forw = MEMNEXT(forw);
383         forwok = 0;
384         while(forw){
385                 if (forw->tag1 != MEMTAG1 || forw->tag2 != MEMTAG2) break;
386                 forwok = forw;
387                 if (forw->next) forw = MEMNEXT(forw->next);
388                 else forw = 0;
389         }
390
391         back = (MemHead *) membase->last;
392         if (back) back = MEMNEXT(back);
393         backok = 0;
394         while(back){
395                 if (back->tag1 != MEMTAG1 || back->tag2 != MEMTAG2) break;
396                 backok = back;
397                 if (back->prev) back = MEMNEXT(back->prev);
398                 else back = 0;
399         }
400
401         if (forw != back) return ("MORE THAN 1 MEMORYBLOCK CORRUPT");
402
403         if (forw == 0 && back == 0){
404                 /* geen foute headers gevonden dan maar op zoek naar memblock*/
405
406                 forw = membase->first;
407                 if (forw) forw = MEMNEXT(forw);
408                 forwok = 0;
409                 while(forw){
410                         if (forw == memh) break;
411                         if (forw->tag1 != MEMTAG1 || forw->tag2 != MEMTAG2) break;
412                         forwok = forw;
413                         if (forw->next) forw = MEMNEXT(forw->next);
414                         else forw = 0;
415                 }
416                 if (forw == 0) return (0);
417
418                 back = (MemHead *) membase->last;
419                 if (back) back = MEMNEXT(back);
420                 backok = 0;
421                 while(back){
422                         if (back == memh) break;
423                         if (back->tag1 != MEMTAG1 || back->tag2 != MEMTAG2) break;
424                         backok = back;
425                         if (back->prev) back = MEMNEXT(back->prev);
426                         else back = 0;
427                 }
428         }
429
430         if (forwok) name = forwok->nextname;
431         else name = "No name found";
432
433         if (forw == memh){
434                 /* voor alle zekerheid wordt dit block maar uit de lijst gehaald */
435                 if (forwok){
436                         if (backok){
437                                 forwok->next = (MemHead *)&backok->next;
438                                 backok->prev = (MemHead *)&forwok->next;
439                                 forwok->nextname = backok->name;
440                         } else{
441                                 forwok->next = 0;
442                                 membase->last = (struct localLink *) &forwok->next; 
443 /*                              membase->last = (struct Link *) &forwok->next; */
444                         }
445                 } else{
446                         if (backok){
447                                 backok->prev = 0;
448                                 membase->first = &backok->next;
449                         } else{
450                                 membase->first = membase->last = 0;
451                         }
452                 }
453         } else{
454                 MemorY_ErroR(name,"Additional error in header");
455                 return("Additional error in header");
456         }
457
458         return(name);
459 }
460
461 /* eof */