1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
|
byte unregisterptr(void *ptr, uint_32 size) //Remove pointer from registration (only if original pointer)?
{
int index;
initZalloc(); //Make sure we're started!
if ((index = matchptr(ptr,0,size,NULL))>-1) //We've been found fully?
{
if (registeredpointers[index].pointer==ptr && registeredpointers[index].size==size) //Fully matched (parents only)?
{
registeredpointers[index].pointer = NULL; //Not a pointer!
registeredpointers[index].size = 0; //No size: we're not a pointer!
#ifdef DEBUG_ALLOCDEALLOC
if (allow_zallocfaillog) dolog("zalloc","Freeing pointer %s with size %i bytes...",registeredpointers[index].name,size); //Show we're freeing this!
#endif
memset(®isteredpointers[index].name,0,sizeof(registeredpointers[index].name)); //Clear the name!
return 1; //Safely unregistered!
}
}
return 0; //We could't find the pointer to unregister!
}
//Core allocation/deallocation functions.
void zalloc_free(void **ptr, uint_32 size) //Free a pointer (used internally only) allocated with nzalloc/zalloc!
{
void *ptrdata = NULL;
initZalloc(); //Make sure we're started!
if (ptr) //Valid pointer to our pointer?
{
ptrdata = *ptr; //Read the current pointer!
if (unregisterptr(ptrdata,size)) //Safe unregister, keeping parents alive, use the copy: the original pointer is destroyed by free in Visual C++?!
{
free(ptrdata); //Release the valid allocated pointer!
}
*ptr = NULL; //Release the pointer given!
}
}
OPTINLINE void *nzalloc(uint_32 size, char *name) //Allocates memory, NULL on failure (ran out of memory), protected malloc!
{
void *ptr = NULL;
int times=10; //Try 10 times till giving up!
initZalloc(); //Make sure we're started!
if (!size) return NULL; //Can't allocate nothing!
for (;(!ptr && times);) //Try for some times!
{
ptr = malloc(size); //Try to allocate!
--times; //Next try!
}
if (ptr!=NULL) //Allocated and a valid size?
{
if (registerptr(ptr,size,name,&zalloc_free)) //Register the pointer with the detection system!
{
return ptr; //Give the original pointer, cleared to 0!
}
#ifdef DEBUG_ALLOCDEALLOC
if (allow_zallocfaillog) dolog("zalloc","Ran out of registrations while allocating %i bytes of data for block %s.",size,name);
#endif
free(ptr); //Free it, can't generate any more!
}
#ifdef DEBUG_ALLOCDEALLOC
else if (allow_zallocfaillog)
{
if (freemem()>=size) //Enough memory after all?
{
dolog("zalloc","Error while allocating %i bytes of data for block \"%s\" with enough free memory(%i bytes).",size,name,freemem());
}
else
{
dolog("zalloc","Ran out of memory while allocating %i bytes of data for block \"%s\".",size,name);
}
}
#endif
return NULL; //Not allocated!
}
//Deallocation core function.
void freez(void **ptr, uint_32 size, char *name)
{
int ptrn=-1;
initZalloc(); //Make sure we're started!
if (!ptr) return; //Invalid pointer to deref!
if ((ptrn = matchptr(*ptr,0,size,NULL))>-1) //Found fully existant?
{
if (!registeredpointers[ptrn].dealloc) //Deallocation not registered?
{
return; //We can't be freed using this function! We're still allocated!
}
registeredpointers[ptrn].dealloc(ptr,size); //Release the memory tied to it using the registered deallocation function, if any!
}
#ifdef DEBUG_ALLOCDEALLOC
else if (allow_zallocfaillog && ptr!=NULL) //An pointer pointing to nothing?
{
dolog("zalloc","Warning: freeing pointer which isn't an allocated reference: %s=%p",name,*ptr); //Log it!
}
#endif
//Still allocated, we might be a pointer which is a subset, so we can't deallocate!
}
//Allocation support: add initialization to zero.
OPTINLINE void *zalloc(uint_32 size, char *name) //Same as nzalloc, but clears the allocated memory!
{
void *ptr;
ptr = nzalloc(size,name); //Try to allocate!
if (ptr) //Allocated?
{
return memset(ptr,0,size); //Give the original pointer, cleared to 0!
}
return NULL; //Not allocated!
}
//Deallocation support: release all registered pointers! This used to be unregisterptrall.
void freezall() //Free all allocated memory still allocated (on shutdown only, garbage collector)!
{
int i;
initZalloc(); //Make sure we're started!
for (i=0;i<NUMITEMS(registeredpointers);i++)
{
freez(®isteredpointers[i].pointer,registeredpointers[i].size,"Unregisterptrall"); //Unregister a pointer when allowed!
}
}
//Memory protection/verification function. Returns the pointer when valid, NULL on invalid.
void *memprotect(void *ptr, uint_32 size, char *name) //Checks address of pointer!
{
if (!ptr || ptr==NULL) //Invalid?
{
return NULL; //Invalid!
}
if (matchptr(ptr,0,size,name)>-2) //Pointer matched (partly or fully)?
{
return ptr; //Give the pointer!
}
return NULL; //Invalid!
}
//Detect free memory.
OPTINLINE uint_32 freemem() //Free memory left! We work!
{
uint_32 curalloc; //Current allocated memory!
char *buffer;
uint_32 multiplier; //The multiplier!
byte times = 9; //Times!
uint_32 lastzalloc = 0;
byte allocated = 0; //Allocated?
curalloc = 0; //Reset at 1 bytes!
multiplier = MEM_MAX_10; //Start at max multiplier (~100MB)!
times = 9; //Times 9 to start with!
allow_zallocfaillog = 0; //Don't allow!
while (1) //While not done...
{
lastzalloc = (curalloc+(multiplier*times)); //Last zalloc!
allocated = 0; //Default: not allocated!
buffer = (char *)zalloc(lastzalloc,"freememdetect"); //Try allocating, don't have to be cleared!
if (buffer) //Allocated?
{
freez((void **)&buffer,lastzalloc,"freememdetect"); //Release memory for next try!
buffer = NULL; //Not allocated anymore!
curalloc = lastzalloc; //Set detected memory!
//dolog("zalloc","Free memory step: %i",curalloc); //Show our step! WE WORK!
allocated = 1; //We're allocated!
}
if (!times || allocated) //Either nothing left or allocated?
{
multiplier /= 10; //Next digit!
times = 9; //Reset times for next try!
}
else //Calculate next digit!
{
--times; //Next digit!
}
if (!multiplier) //Gotten an allocation and/or done?
{
break; //Stop searching: we're done!
}
//We're to continue!
} //We have success!
if (buffer) //Still allocated?
{
freez((void **)&buffer,lastzalloc,"Freemem@FinalCleanup"); //Still allocated=>release?
}
allow_zallocfaillog = 1; //Allow again!
#ifdef MEM_BLOCK_LIMIT
if (curalloc > MEM_BLOCK_LIMIT) //More than the limit?
{
curalloc = MEM_BLOCK_LIMIT; //Limit to this much!
}
#endif
return curalloc; //Give free allocatable memory size!
}
|