It appears that removing the 'int level' field from the MemHead struct caused alignment issues for gcc builds of blender on Irix (zr, who removed this field, commented that this problem might occur, and sure enough it did happen). I've renamed the field from 'level' to 'pad' to reflect that it has no meaning beyond addressing alignment issues.
468 lines
11 KiB
C
468 lines
11 KiB
C
/**
|
|
* $Id$
|
|
* ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version. The Blender
|
|
* Foundation also sells licenses for use in proprietary software under
|
|
* the Blender License. See http://www.blender.org/BL/ for information
|
|
* about this.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*
|
|
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
|
|
* All rights reserved.
|
|
*
|
|
* The Original Code is: all of this file.
|
|
*
|
|
* Contributor(s): none yet.
|
|
*
|
|
* ***** END GPL/BL DUAL LICENSE BLOCK *****
|
|
*/
|
|
|
|
/**
|
|
|
|
* $Id$
|
|
* Copyright (C) 2001 NaN Technologies B.V.
|
|
* Guarded memory allocation, and boundary-write detection.
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h> /* memcpy */
|
|
#include <stdarg.h>
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
/* --------------------------------------------------------------------- */
|
|
/* Data definition */
|
|
/* --------------------------------------------------------------------- */
|
|
/* all memory chunks are put in linked lists */
|
|
typedef struct localLink
|
|
{
|
|
struct localLink *next,*prev;
|
|
} localLink;
|
|
|
|
typedef struct localListBase
|
|
{
|
|
void *first, *last;
|
|
} localListBase;
|
|
|
|
typedef struct MemHead {
|
|
int tag1;
|
|
int len;
|
|
struct MemHead *next,*prev;
|
|
char * name;
|
|
char * nextname;
|
|
int tag2;
|
|
int pad; /* keep this in, due to alignment issues (e.g., irix/gcc) - Hos */
|
|
} MemHead;
|
|
|
|
typedef struct MemTail {
|
|
int tag3, pad;
|
|
} MemTail;
|
|
|
|
/* --------------------------------------------------------------------- */
|
|
/* local functions */
|
|
/* --------------------------------------------------------------------- */
|
|
|
|
static void addtail(localListBase *listbase, void *vlink);
|
|
static void remlink(localListBase *listbase, void *vlink);
|
|
static void rem_memblock(MemHead *memh);
|
|
static void MemorY_ErroR(char *block, char *error);
|
|
static char *check_memlist(MemHead *memh);
|
|
|
|
/* --------------------------------------------------------------------- */
|
|
/* locally used defines */
|
|
/* --------------------------------------------------------------------- */
|
|
|
|
#if defined( __sgi) || defined (__sun) || defined (__sun__) || defined (__sparc) || defined (__sparc__) || defined (__PPC__) || defined (__APPLE__)
|
|
#define MAKE_ID(a,b,c,d) ( (int)(a)<<24 | (int)(b)<<16 | (c)<<8 | (d) )
|
|
#else
|
|
#define MAKE_ID(a,b,c,d) ( (int)(d)<<24 | (int)(c)<<16 | (b)<<8 | (a) )
|
|
#endif
|
|
|
|
#define MEMTAG1 MAKE_ID('M', 'E', 'M', 'O')
|
|
#define MEMTAG2 MAKE_ID('R', 'Y', 'B', 'L')
|
|
#define MEMTAG3 MAKE_ID('O', 'C', 'K', '!')
|
|
#define MEMFREE MAKE_ID('F', 'R', 'E', 'E')
|
|
|
|
#define MEMNEXT(x) ((MemHead *)(((char *) x) - ((char *) & (((MemHead *)0)->next))))
|
|
|
|
/* --------------------------------------------------------------------- */
|
|
/* vars */
|
|
/* --------------------------------------------------------------------- */
|
|
|
|
|
|
int totblock= 0;
|
|
int mem_in_use= 0;
|
|
|
|
static struct localListBase _membase;
|
|
static struct localListBase *membase = &_membase;
|
|
static void (*error_callback)(char *) = NULL;
|
|
|
|
#ifdef malloc
|
|
#undef malloc
|
|
#endif
|
|
|
|
#ifdef calloc
|
|
#undef calloc
|
|
#endif
|
|
|
|
#ifdef free
|
|
#undef free
|
|
#endif
|
|
|
|
|
|
/* --------------------------------------------------------------------- */
|
|
/* implementation */
|
|
/* --------------------------------------------------------------------- */
|
|
|
|
static void print_error(char *str, ...)
|
|
{
|
|
char buf[1024];
|
|
va_list ap;
|
|
|
|
va_start(ap, str);
|
|
vsprintf(buf, str, ap);
|
|
va_end(ap);
|
|
|
|
if (error_callback) error_callback(buf);
|
|
}
|
|
|
|
int MEM_check_memory_integrity()
|
|
{
|
|
char* err_val = NULL;
|
|
MemHead* listend;
|
|
/* check_memlist starts from the front, and runs until it finds
|
|
* the requested chunk. For this test, that's the last one. */
|
|
listend = membase->last;
|
|
|
|
err_val = check_memlist(listend);
|
|
|
|
return (int)err_val;
|
|
}
|
|
|
|
|
|
void MEM_set_error_callback(void (*func)(char *))
|
|
{
|
|
error_callback = func;
|
|
}
|
|
|
|
|
|
int MEM_allocN_len(void *vmemh)
|
|
{
|
|
if (vmemh) {
|
|
MemHead *memh= vmemh;
|
|
|
|
memh--;
|
|
return memh->len;
|
|
} else
|
|
return 0;
|
|
}
|
|
|
|
void *MEM_dupallocN(void *vmemh)
|
|
{
|
|
void *newp= NULL;
|
|
|
|
if (vmemh) {
|
|
MemHead *memh= vmemh;
|
|
memh--;
|
|
|
|
newp= MEM_mallocN(memh->len, "dupli_alloc");
|
|
memcpy(newp, vmemh, memh->len);
|
|
}
|
|
|
|
return newp;
|
|
}
|
|
|
|
void *MEM_mallocN(unsigned int len, char *str)
|
|
{
|
|
MemHead *memh;
|
|
MemTail *memt;
|
|
|
|
len = (len + 3 ) & ~3; /* allocate in units of 4 */
|
|
|
|
memh= (MemHead *)malloc(len+sizeof(MemHead)+sizeof(MemTail));
|
|
|
|
if(memh!=0) {
|
|
memh->tag1 = MEMTAG1;
|
|
memh->name = str;
|
|
memh->nextname = 0;
|
|
memh->len = len;
|
|
/* memh->level = 0; */
|
|
memh->tag2 = MEMTAG2;
|
|
|
|
memt = (MemTail *)(((char *) memh) + sizeof(MemHead) + len);
|
|
memt->tag3 = MEMTAG3;
|
|
|
|
addtail(membase,&memh->next);
|
|
if (memh->next) memh->nextname = MEMNEXT(memh->next)->name;
|
|
|
|
totblock++;
|
|
mem_in_use += len;
|
|
return (++memh);
|
|
}
|
|
print_error("Malloc returns nill: len=%d in %s\n",len,str);
|
|
return 0;
|
|
}
|
|
|
|
void *MEM_callocN(unsigned int len, char *str)
|
|
{
|
|
MemHead *memh;
|
|
MemTail *memt;
|
|
|
|
len = (len + 3 ) & ~3; /* allocate in units of 4 */
|
|
|
|
memh= (MemHead *)calloc(len+sizeof(MemHead)+sizeof(MemTail),1);
|
|
|
|
if(memh!=0) {
|
|
memh->tag1 = MEMTAG1;
|
|
memh->name = str;
|
|
memh->nextname = 0;
|
|
memh->len = len;
|
|
/* memh->level = 0; */
|
|
memh->tag2 = MEMTAG2;
|
|
|
|
memt = (MemTail *)(((char *) memh) + sizeof(MemHead) + len);
|
|
memt->tag3 = MEMTAG3;
|
|
|
|
addtail(membase,&memh->next);
|
|
if (memh->next) memh->nextname = MEMNEXT(memh->next)->name;
|
|
|
|
totblock++;
|
|
mem_in_use += len;
|
|
return (++memh);
|
|
}
|
|
print_error("Calloc returns nill: len=%d in %s\n",len,str);
|
|
return 0;
|
|
}
|
|
|
|
|
|
void MEM_printmemlist()
|
|
{
|
|
MemHead *membl;
|
|
|
|
membl = membase->first;
|
|
if (membl) membl = MEMNEXT(membl);
|
|
while(membl) {
|
|
print_error("%s len: %d %p\n",membl->name,membl->len, membl+1);
|
|
if(membl->next)
|
|
membl= MEMNEXT(membl->next);
|
|
else break;
|
|
}
|
|
}
|
|
|
|
short MEM_freeN(void *vmemh) /* anders compileertie niet meer */
|
|
{
|
|
short error = 0;
|
|
MemTail *memt;
|
|
MemHead *memh= vmemh;
|
|
char *name;
|
|
|
|
if (memh == 0){
|
|
MemorY_ErroR("free","attempt to free NULL pointer");
|
|
/* print_error(err_stream, "%d\n", (memh+4000)->tag1); */
|
|
return(-1);
|
|
}
|
|
|
|
if(sizeof(long)==8) {
|
|
if (((long) memh) & 0x7) {
|
|
MemorY_ErroR("free","attempt to free illegal pointer");
|
|
return(-1);
|
|
}
|
|
}
|
|
else {
|
|
if (((long) memh) & 0x3) {
|
|
MemorY_ErroR("free","attempt to free illegal pointer");
|
|
return(-1);
|
|
}
|
|
}
|
|
|
|
memh--;
|
|
if(memh->tag1 == MEMFREE && memh->tag2 == MEMFREE) {
|
|
MemorY_ErroR(memh->name,"double free");
|
|
return(-1);
|
|
}
|
|
|
|
if ((memh->tag1 == MEMTAG1) && (memh->tag2 == MEMTAG2) && ((memh->len & 0x3) == 0)) {
|
|
memt = (MemTail *)(((char *) memh) + sizeof(MemHead) + memh->len);
|
|
if (memt->tag3 == MEMTAG3){
|
|
|
|
memh->tag1 = MEMFREE;
|
|
memh->tag2 = MEMFREE;
|
|
memt->tag3 = MEMFREE;
|
|
/* na tags !!! */
|
|
rem_memblock(memh);
|
|
|
|
return(0);
|
|
}
|
|
error = 2;
|
|
MemorY_ErroR(memh->name,"end corrupt");
|
|
name = check_memlist(memh);
|
|
if (name != 0){
|
|
if (name != memh->name) MemorY_ErroR(name,"is also corrupt");
|
|
}
|
|
} else{
|
|
error = -1;
|
|
name = check_memlist(memh);
|
|
if (name == 0) MemorY_ErroR("free","pointer not in memlist");
|
|
else MemorY_ErroR(name,"error in header");
|
|
}
|
|
|
|
totblock--;
|
|
/* hier moet een DUMP plaatsvinden */
|
|
|
|
return(error);
|
|
}
|
|
|
|
/* --------------------------------------------------------------------- */
|
|
/* local functions */
|
|
/* --------------------------------------------------------------------- */
|
|
|
|
static void addtail(localListBase *listbase, void *vlink)
|
|
{
|
|
struct localLink *link= vlink;
|
|
|
|
if (link == 0) return;
|
|
if (listbase == 0) return;
|
|
|
|
link->next = 0;
|
|
link->prev = listbase->last;
|
|
|
|
if (listbase->last) ((struct localLink *)listbase->last)->next = link;
|
|
if (listbase->first == 0) listbase->first = link;
|
|
listbase->last = link;
|
|
}
|
|
|
|
static void remlink(localListBase *listbase, void *vlink)
|
|
{
|
|
struct localLink *link= vlink;
|
|
|
|
if (link == 0) return;
|
|
if (listbase == 0) return;
|
|
|
|
if (link->next) link->next->prev = link->prev;
|
|
if (link->prev) link->prev->next = link->next;
|
|
|
|
if (listbase->last == link) listbase->last = link->prev;
|
|
if (listbase->first == link) listbase->first = link->next;
|
|
}
|
|
|
|
static void rem_memblock(MemHead *memh)
|
|
{
|
|
remlink(membase,&memh->next);
|
|
if (memh->prev){
|
|
if (memh->next) MEMNEXT(memh->prev)->nextname = MEMNEXT(memh->next)->name;
|
|
else MEMNEXT(memh->prev)->nextname = 0;
|
|
}
|
|
|
|
totblock--;
|
|
mem_in_use -= memh->len;
|
|
free(memh);
|
|
}
|
|
|
|
static void MemorY_ErroR(char *block, char *error)
|
|
{
|
|
print_error("Memoryblock %s: %s\n",block,error);
|
|
}
|
|
|
|
static char *check_memlist(MemHead *memh)
|
|
{
|
|
MemHead *forw,*back,*forwok,*backok;
|
|
char *name;
|
|
|
|
forw = membase->first;
|
|
if (forw) forw = MEMNEXT(forw);
|
|
forwok = 0;
|
|
while(forw){
|
|
if (forw->tag1 != MEMTAG1 || forw->tag2 != MEMTAG2) break;
|
|
forwok = forw;
|
|
if (forw->next) forw = MEMNEXT(forw->next);
|
|
else forw = 0;
|
|
}
|
|
|
|
back = (MemHead *) membase->last;
|
|
if (back) back = MEMNEXT(back);
|
|
backok = 0;
|
|
while(back){
|
|
if (back->tag1 != MEMTAG1 || back->tag2 != MEMTAG2) break;
|
|
backok = back;
|
|
if (back->prev) back = MEMNEXT(back->prev);
|
|
else back = 0;
|
|
}
|
|
|
|
if (forw != back) return ("MORE THAN 1 MEMORYBLOCK CORRUPT");
|
|
|
|
if (forw == 0 && back == 0){
|
|
/* geen foute headers gevonden dan maar op zoek naar memblock*/
|
|
|
|
forw = membase->first;
|
|
if (forw) forw = MEMNEXT(forw);
|
|
forwok = 0;
|
|
while(forw){
|
|
if (forw == memh) break;
|
|
if (forw->tag1 != MEMTAG1 || forw->tag2 != MEMTAG2) break;
|
|
forwok = forw;
|
|
if (forw->next) forw = MEMNEXT(forw->next);
|
|
else forw = 0;
|
|
}
|
|
if (forw == 0) return (0);
|
|
|
|
back = (MemHead *) membase->last;
|
|
if (back) back = MEMNEXT(back);
|
|
backok = 0;
|
|
while(back){
|
|
if (back == memh) break;
|
|
if (back->tag1 != MEMTAG1 || back->tag2 != MEMTAG2) break;
|
|
backok = back;
|
|
if (back->prev) back = MEMNEXT(back->prev);
|
|
else back = 0;
|
|
}
|
|
}
|
|
|
|
if (forwok) name = forwok->nextname;
|
|
else name = "No name found";
|
|
|
|
if (forw == memh){
|
|
/* voor alle zekerheid wordt dit block maar uit de lijst gehaald */
|
|
if (forwok){
|
|
if (backok){
|
|
forwok->next = (MemHead *)&backok->next;
|
|
backok->prev = (MemHead *)&forwok->next;
|
|
forwok->nextname = backok->name;
|
|
} else{
|
|
forwok->next = 0;
|
|
membase->last = (struct localLink *) &forwok->next;
|
|
/* membase->last = (struct Link *) &forwok->next; */
|
|
}
|
|
} else{
|
|
if (backok){
|
|
backok->prev = 0;
|
|
membase->first = &backok->next;
|
|
} else{
|
|
membase->first = membase->last = 0;
|
|
}
|
|
}
|
|
} else{
|
|
MemorY_ErroR(name,"Additional error in header");
|
|
return("Additional error in header");
|
|
}
|
|
|
|
return(name);
|
|
}
|
|
|
|
/* eof */
|