#include <cstdio>
#include <cstdlib>
#include <cstring>
#include "wwwi/mutex.h"
#include "wwwi/os.h"
enum new_type_enum { NEW_SIMPLE, NEW_ARRAY };
typedef enum new_type_enum NewType;
const unsigned _wwwi_magic = 0xdeadc0de;
#ifdef WWWI_QNX
const unsigned _wwwi_leftover = 15;
#endif
#ifdef freebsd
const unsigned _wwwi_leftover = 3;
#endif
struct mem_footer_struct {
unsigned uMagic;
};
typedef struct mem_footer_struct MemFooter;
typedef MemFooter* MemFooterPtr;
struct mem_header_struct {
unsigned uMagic0;
bool bAllocated;
NewType newType;
MemFooterPtr memFooterPtr;
size_t szAlloc;
unsigned uMagic1;
};
typedef struct mem_header_struct MemHeader;
typedef MemHeader* MemHeaderPtr;
using namespace std;
void _wwwi_atexit(void);
void _wwwi_free(void*,NewType);
void _wwwi_init(void);
void *_wwwi_malloc(size_t,NewType);
void _wwwi_table_add(MemHeaderPtr);
void _wwwi_table_remove(MemHeaderPtr);
unsigned _wwwi_count = 0;
MemHeaderPtr *_wwwi_table = NULL;
unsigned _wwwi_table_size = 0;
void *operator new(size_t i_szAlloc) {
return _wwwi_malloc(i_szAlloc,NEW_SIMPLE);
}
void *operator new[](size_t i_szAlloc) {
return _wwwi_malloc(i_szAlloc,NEW_ARRAY);
}
void *_wwwi_malloc(size_t i_szAlloc, NewType newType) {
static bool bInit = false;
if (bInit==false) {
_wwwi_init();
bInit = true;
}
size_t szAdjusted = i_szAlloc + sizeof(MemHeader) + sizeof(MemFooter);
char *pcMalloc = (char*)malloc(szAdjusted);
if (pcMalloc==NULL) {
fprintf(stderr,"malloc() failed\n");
abort();
}
MemHeaderPtr mhp = (MemHeaderPtr)pcMalloc;
pcMalloc = (char*)(mhp+1);
MemFooterPtr mfp = (MemFooterPtr)(pcMalloc+i_szAlloc);
mhp->uMagic0 = _wwwi_magic;
mhp->bAllocated = true;
mhp->newType = newType;
mhp->memFooterPtr = mfp;
mhp->szAlloc = i_szAlloc;
mhp->uMagic1 = _wwwi_magic;
mfp->uMagic = _wwwi_magic;
_wwwi_table_add(mhp);
_wwwi_count++;
return pcMalloc;
}
void operator delete(void *pv) {
_wwwi_free(pv,NEW_SIMPLE);
}
void operator delete[](void *pv) {
_wwwi_free(pv,NEW_ARRAY);
}
void _wwwi_free(void *pv, NewType newType) {
if (pv==NULL) return;
MemHeaderPtr mhp = ((MemHeaderPtr)pv) - 1;
if(mhp->uMagic0!=_wwwi_magic) {
fprintf(stderr,"delete: invalid pointer\n");
abort();
}
if(mhp->uMagic1!=_wwwi_magic) {
fprintf(stderr,"delete: block %08X stepped under bounds\n",(unsigned)pv);
abort();
}
if(mhp->bAllocated==false) {
fprintf(stderr,"delete: block %08X already freed\n",(unsigned)pv);
abort();
}
mhp->bAllocated = false;
if(mhp->newType!=newType) {
fprintf(stderr,"delete: block %08X allocated with %s but freed with %s\n",(unsigned)pv,((mhp->newType==NEW_SIMPLE)?"new":"new[]"),((newType==NEW_SIMPLE)?"new":"new[]"));
abort();
}
if(mhp->memFooterPtr->uMagic!=_wwwi_magic) {
fprintf(stderr,"delete: block %08X stepped over bounds\n",(unsigned)pv);
abort();
}
if (_wwwi_count==0) {
fprintf(stderr,"delete: more blocks deleted than allocated\n");
abort();
}
_wwwi_count--;
_wwwi_table_remove(mhp);
memset(pv,0xcc,mhp->szAlloc);
free((void*)mhp);
}
void _wwwi_init() {
fprintf(stderr,"WWWI debugging allocator in use\n");
if (atexit(_wwwi_atexit)!=0) {
fprintf(stderr,"_wwwi_init: atexit() failed\n");
abort();
}
_wwwi_table_size = 32;
_wwwi_table = (MemHeaderPtr*)malloc(sizeof(MemHeaderPtr)*_wwwi_table_size);
if (_wwwi_table==NULL) {
fprintf(stderr,"_wwwi_init: could not allocate malloc table\n");
abort();
}
memset(_wwwi_table,0,sizeof(MemHeaderPtr)*_wwwi_table_size);
}
void _wwwi_atexit() {
unsigned u;
if (_wwwi_count!=0) {
fprintf(stderr,"_wwwi_atexit: %u blocks were not deleted, %u is normal\n",_wwwi_count,_wwwi_leftover);
}
for(u=0;u<_wwwi_table_size;u++) {
if (_wwwi_table[u]==NULL) continue;
fprintf(stderr,"block not freed: %u bytes at %08X\n",_wwwi_table[u]->szAlloc,(unsigned)(_wwwi_table[u]+1));
}
}
void _wwwi_table_add(MemHeaderPtr i_mhp) {
unsigned u;
MemHeaderPtr *mhpTableNew;
for(u=0;u<_wwwi_table_size;u++) {
if (_wwwi_table[u]!=NULL) continue;
_wwwi_table[u] = i_mhp;
return;
}
_wwwi_table_size *= 2;
mhpTableNew = (MemHeaderPtr*)realloc(_wwwi_table,sizeof(MemHeaderPtr)*_wwwi_table_size);
if(mhpTableNew==NULL) {
fprintf(stderr,"_wwwi_add_table: table grow to %u failed\n",_wwwi_table_size);
abort();
}
_wwwi_table = mhpTableNew;
for(u=_wwwi_table_size/2;u<_wwwi_table_size;u++) _wwwi_table[u] = NULL;
fprintf(stderr,"_wwwi_add_table: table grows to %u\n",_wwwi_table_size);
_wwwi_table[_wwwi_table_size/2] = i_mhp;
}
void _wwwi_table_remove(MemHeaderPtr i_mhp) {
unsigned u;
for(u=0;u<_wwwi_table_size;u++) {
if (_wwwi_table[u]!=i_mhp) continue;
_wwwi_table[u] = NULL;
return;
}
fprintf(stderr,"_wwwi_table_remove: block not in table\n");
abort();
}