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