/* * xmlmemory.c: libxml memory allocator wrapper. * * Author: Daniel Veillard */ #define IN_LIBXML #include "libxml.h" #include #include #include #include #include #include #include #include #include "private/error.h" #include "private/memory.h" #include "private/threads.h" static unsigned long debugMemSize = 0; static unsigned long debugMemBlocks = 0; static xmlMutex xmlMemMutex; /************************************************************************ * * * Macros, variables and associated types * * * ************************************************************************/ /* * Each of the blocks allocated begin with a header containing information */ #define MEMTAG 0x5aa5U typedef struct memnod { unsigned int mh_tag; size_t mh_size; } MEMHDR; #ifdef SUN4 #define ALIGN_SIZE 16 #else #define ALIGN_SIZE sizeof(double) #endif #define RESERVE_SIZE (((sizeof(MEMHDR) + ALIGN_SIZE - 1) \ / ALIGN_SIZE ) * ALIGN_SIZE) #define MAX_SIZE_T ((size_t)-1) #define CLIENT_2_HDR(a) ((void *) (((char *) (a)) - RESERVE_SIZE)) #define HDR_2_CLIENT(a) ((void *) (((char *) (a)) + RESERVE_SIZE)) /** * @deprecated don't use * * @param size an int specifying the size in byte to allocate. * @param file the file name or NULL * @param line the line number * @returns a pointer to the allocated area or NULL in case of lack of memory. */ void * xmlMallocLoc(size_t size, const char *file ATTRIBUTE_UNUSED, int line ATTRIBUTE_UNUSED) { return(xmlMemMalloc(size)); } /** * @deprecated don't use * * @param size an unsigned int specifying the size in byte to allocate. * @param file the file name or NULL * @param line the line number * @returns a pointer to the allocated area or NULL in case of lack of memory. */ void * xmlMallocAtomicLoc(size_t size, const char *file ATTRIBUTE_UNUSED, int line ATTRIBUTE_UNUSED) { return(xmlMemMalloc(size)); } /** * a malloc() equivalent, with logging of the allocation info. * * @param size an int specifying the size in byte to allocate. * @returns a pointer to the allocated area or NULL in case of lack of memory. */ void * xmlMemMalloc(size_t size) { MEMHDR *p; xmlInitParser(); if (size > (MAX_SIZE_T - RESERVE_SIZE)) return(NULL); p = (MEMHDR *) malloc(RESERVE_SIZE + size); if (!p) return(NULL); p->mh_tag = MEMTAG; p->mh_size = size; xmlMutexLock(&xmlMemMutex); debugMemSize += size; debugMemBlocks++; xmlMutexUnlock(&xmlMemMutex); return(HDR_2_CLIENT(p)); } /** * @deprecated don't use * * @param ptr the initial memory block pointer * @param size an int specifying the size in byte to allocate. * @param file the file name or NULL * @param line the line number * @returns a pointer to the allocated area or NULL in case of lack of memory. */ void * xmlReallocLoc(void *ptr, size_t size, const char *file ATTRIBUTE_UNUSED, int line ATTRIBUTE_UNUSED) { return(xmlMemRealloc(ptr, size)); } /** * a realloc() equivalent, with logging of the allocation info. * * @param ptr the initial memory block pointer * @param size an int specifying the size in byte to allocate. * @returns a pointer to the allocated area or NULL in case of lack of memory. */ void * xmlMemRealloc(void *ptr, size_t size) { MEMHDR *p, *tmp; size_t oldSize; if (ptr == NULL) return(xmlMemMalloc(size)); xmlInitParser(); if (size > (MAX_SIZE_T - RESERVE_SIZE)) return(NULL); p = CLIENT_2_HDR(ptr); if (p->mh_tag != MEMTAG) { xmlPrintErrorMessage("xmlMemRealloc: Tag error\n"); return(NULL); } oldSize = p->mh_size; p->mh_tag = ~MEMTAG; tmp = (MEMHDR *) realloc(p, RESERVE_SIZE + size); if (!tmp) { p->mh_tag = MEMTAG; return(NULL); } p = tmp; p->mh_tag = MEMTAG; p->mh_size = size; xmlMutexLock(&xmlMemMutex); debugMemSize -= oldSize; debugMemSize += size; xmlMutexUnlock(&xmlMemMutex); return(HDR_2_CLIENT(p)); } /** * a free() equivalent, with error checking. * * @param ptr the memory block pointer */ void xmlMemFree(void *ptr) { MEMHDR *p; if (ptr == NULL) return; if (ptr == (void *) -1) { xmlPrintErrorMessage("xmlMemFree: Pointer from freed area\n"); return; } p = CLIENT_2_HDR(ptr); if (p->mh_tag != MEMTAG) { xmlPrintErrorMessage("xmlMemFree: Tag error\n"); return; } p->mh_tag = ~MEMTAG; memset(ptr, -1, p->mh_size); xmlMutexLock(&xmlMemMutex); debugMemSize -= p->mh_size; debugMemBlocks--; xmlMutexUnlock(&xmlMemMutex); free(p); } /** * @deprecated don't use * * @param str the initial string pointer * @param file the file name or NULL * @param line the line number * @returns a pointer to the new string or NULL if allocation error occurred. */ char * xmlMemStrdupLoc(const char *str, const char *file ATTRIBUTE_UNUSED, int line ATTRIBUTE_UNUSED) { return(xmlMemoryStrdup(str)); } /** * a strdup() equivalent, with logging of the allocation info. * * @param str the initial string pointer * @returns a pointer to the new string or NULL if allocation error occurred. */ char * xmlMemoryStrdup(const char *str) { char *s; size_t size = strlen(str) + 1; MEMHDR *p; xmlInitParser(); if (size > (MAX_SIZE_T - RESERVE_SIZE)) return(NULL); p = (MEMHDR *) malloc(RESERVE_SIZE + size); if (!p) return(NULL); p->mh_tag = MEMTAG; p->mh_size = size; xmlMutexLock(&xmlMemMutex); debugMemSize += size; debugMemBlocks++; xmlMutexUnlock(&xmlMemMutex); s = (char *) HDR_2_CLIENT(p); memcpy(s, str, size); return(s); } /** * @param ptr pointer to the memory allocation * @returns the size of a memory allocation. */ size_t xmlMemSize(void *ptr) { MEMHDR *p; if (ptr == NULL) return(0); p = CLIENT_2_HDR(ptr); if (p->mh_tag != MEMTAG) return(0); return(p->mh_size); } /** * Provides the amount of memory currently allocated * * @returns an int representing the amount of memory allocated. */ int xmlMemUsed(void) { return(debugMemSize); } /** * Provides the number of memory areas currently allocated * * @returns an int representing the number of blocks */ int xmlMemBlocks(void) { int res; xmlMutexLock(&xmlMemMutex); res = debugMemBlocks; xmlMutexUnlock(&xmlMemMutex); return(res); } /** * @deprecated This feature was removed. * @param fp a FILE descriptor * @param nbBytes the amount of memory to dump */ void xmlMemDisplayLast(FILE *fp ATTRIBUTE_UNUSED, long nbBytes ATTRIBUTE_UNUSED) { } /** * @deprecated This feature was removed. * @param fp a FILE descriptor */ void xmlMemDisplay(FILE *fp ATTRIBUTE_UNUSED) { } /** * @deprecated This feature was removed. * @param fp a FILE descriptor * @param nr number of entries to dump */ void xmlMemShow(FILE *fp ATTRIBUTE_UNUSED, int nr ATTRIBUTE_UNUSED) { } /** * @deprecated This feature was removed. */ void xmlMemoryDump(void) { } /**************************************************************** * * * Initialization Routines * * * ****************************************************************/ /** * @deprecated Alias for #xmlInitParser. * * @returns 0. */ int xmlInitMemory(void) { xmlInitParser(); return(0); } /** * Initialize the memory layer. */ void xmlInitMemoryInternal(void) { xmlInitMutex(&xmlMemMutex); } /** * @deprecated This function is a no-op. Call #xmlCleanupParser * to free global state but see the warnings there. #xmlCleanupParser * should be only called once at program exit. In most cases, you don't * have call cleanup functions at all. */ void xmlCleanupMemory(void) { } /** * Free up all the memory allocated by the library for its own * use. This should not be called by user level code. */ void xmlCleanupMemoryInternal(void) { /* * Don't clean up mutex on Windows. Global state destructors can call * malloc functions after xmlCleanupParser was called. If memory * debugging is enabled, xmlMemMutex can be used after cleanup. * * See python/tests/thread2.py */ #if !defined(LIBXML_THREAD_ENABLED) || !defined(_WIN32) xmlCleanupMutex(&xmlMemMutex); #endif } /** * Override the default memory access functions with a new set * This has to be called before any other libxml routines ! * * Should this be blocked if there was already some allocations * done ? * * @param freeFunc the free() function to use * @param mallocFunc the malloc() function to use * @param reallocFunc the realloc() function to use * @param strdupFunc the strdup() function to use * @returns 0 on success */ int xmlMemSetup(xmlFreeFunc freeFunc, xmlMallocFunc mallocFunc, xmlReallocFunc reallocFunc, xmlStrdupFunc strdupFunc) { if (freeFunc == NULL) return(-1); if (mallocFunc == NULL) return(-1); if (reallocFunc == NULL) return(-1); if (strdupFunc == NULL) return(-1); xmlFree = freeFunc; xmlMalloc = mallocFunc; xmlMallocAtomic = mallocFunc; xmlRealloc = reallocFunc; xmlMemStrdup = strdupFunc; return(0); } /** * Provides the memory access functions set currently in use * * @param freeFunc place to save the free() function in use * @param mallocFunc place to save the malloc() function in use * @param reallocFunc place to save the realloc() function in use * @param strdupFunc place to save the strdup() function in use * @returns 0 on success */ int xmlMemGet(xmlFreeFunc *freeFunc, xmlMallocFunc *mallocFunc, xmlReallocFunc *reallocFunc, xmlStrdupFunc *strdupFunc) { if (freeFunc != NULL) *freeFunc = xmlFree; if (mallocFunc != NULL) *mallocFunc = xmlMalloc; if (reallocFunc != NULL) *reallocFunc = xmlRealloc; if (strdupFunc != NULL) *strdupFunc = xmlMemStrdup; return(0); } /** * Override the default memory access functions with a new set * This has to be called before any other libxml routines ! * The mallocAtomicFunc is specialized for atomic block * allocations (i.e. of areas useful for garbage collected memory allocators * * @deprecated Use #xmlMemSetup. * * Should this be blocked if there was already some allocations * done ? * * @param freeFunc the free() function to use * @param mallocFunc the malloc() function to use * @param mallocAtomicFunc the malloc() function to use for atomic allocations * @param reallocFunc the realloc() function to use * @param strdupFunc the strdup() function to use * @returns 0 on success */ int xmlGcMemSetup(xmlFreeFunc freeFunc, xmlMallocFunc mallocFunc, xmlMallocFunc mallocAtomicFunc, xmlReallocFunc reallocFunc, xmlStrdupFunc strdupFunc) { if (freeFunc == NULL) return(-1); if (mallocFunc == NULL) return(-1); if (mallocAtomicFunc == NULL) return(-1); if (reallocFunc == NULL) return(-1); if (strdupFunc == NULL) return(-1); xmlFree = freeFunc; xmlMalloc = mallocFunc; xmlMallocAtomic = mallocAtomicFunc; xmlRealloc = reallocFunc; xmlMemStrdup = strdupFunc; return(0); } /** * Provides the memory access functions set currently in use * The mallocAtomicFunc is specialized for atomic block * allocations (i.e. of areas useful for garbage collected memory allocators * * @deprecated Use #xmlMemGet. * * @param freeFunc place to save the free() function in use * @param mallocFunc place to save the malloc() function in use * @param mallocAtomicFunc place to save the atomic malloc() function in use * @param reallocFunc place to save the realloc() function in use * @param strdupFunc place to save the strdup() function in use * @returns 0 on success */ int xmlGcMemGet(xmlFreeFunc *freeFunc, xmlMallocFunc *mallocFunc, xmlMallocFunc *mallocAtomicFunc, xmlReallocFunc *reallocFunc, xmlStrdupFunc *strdupFunc) { if (freeFunc != NULL) *freeFunc = xmlFree; if (mallocFunc != NULL) *mallocFunc = xmlMalloc; if (mallocAtomicFunc != NULL) *mallocAtomicFunc = xmlMallocAtomic; if (reallocFunc != NULL) *reallocFunc = xmlRealloc; if (strdupFunc != NULL) *strdupFunc = xmlMemStrdup; return(0); }