📄 xmlmemory.c
字号:
/*
* xmlmemory.c: libxml memory allocator wrapper.
*
* daniel@veillard.com
*/
#define IN_LIBXML
#include "libxml.h"
#include <string.h>
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef HAVE_TIME_H
#include <time.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#else
#ifdef HAVE_MALLOC_H
#include <malloc.h>
#endif
#endif
#ifdef HAVE_CTYPE_H
#include <ctype.h>
#endif
/* #define DEBUG_MEMORY */
/**
* MEM_LIST:
*
* keep track of all allocated blocks for error reporting
* Always build the memory list !
*/
#ifdef DEBUG_MEMORY_LOCATION
#ifndef MEM_LIST
#define MEM_LIST /* keep a list of all the allocated memory blocks */
#endif
#endif
#include <libxml/globals.h> /* must come before xmlmemory.h */
#include <libxml/xmlmemory.h>
#include <libxml/xmlerror.h>
#include <libxml/threads.h>
static int xmlMemInitialized = 0;
static unsigned long debugMemSize = 0;
static unsigned long debugMemBlocks = 0;
static unsigned long debugMaxMemSize = 0;
static xmlMutexPtr xmlMemMutex = NULL;
void xmlMallocBreakpoint(void);
/************************************************************************
* *
* Macros, variables and associated types *
* *
************************************************************************/
#if !defined(LIBXML_THREAD_ENABLED) && !defined(LIBXML_THREAD_ALLOC_ENABLED)
#ifdef xmlMalloc
#undef xmlMalloc
#endif
#ifdef xmlRealloc
#undef xmlRealloc
#endif
#ifdef xmlMemStrdup
#undef xmlMemStrdup
#endif
#endif
/*
* Each of the blocks allocated begin with a header containing informations
*/
#define MEMTAG 0x5aa5
#define MALLOC_TYPE 1
#define REALLOC_TYPE 2
#define STRDUP_TYPE 3
#define MALLOC_ATOMIC_TYPE 4
#define REALLOC_ATOMIC_TYPE 5
typedef struct memnod {
unsigned int mh_tag;
unsigned int mh_type;
unsigned long mh_number;
size_t mh_size;
#ifdef MEM_LIST
struct memnod *mh_next;
struct memnod *mh_prev;
#endif
const char *mh_file;
unsigned int mh_line;
} MEMHDR;
#ifdef SUN4
#define ALIGN_SIZE 16
#else
#define ALIGN_SIZE sizeof(double)
#endif
#define HDR_SIZE sizeof(MEMHDR)
#define RESERVE_SIZE (((HDR_SIZE + (ALIGN_SIZE-1)) \
/ ALIGN_SIZE ) * ALIGN_SIZE)
#define CLIENT_2_HDR(a) ((MEMHDR *) (((char *) (a)) - RESERVE_SIZE))
#define HDR_2_CLIENT(a) ((void *) (((char *) (a)) + RESERVE_SIZE))
static unsigned int block=0;
static unsigned int xmlMemStopAtBlock = 0;
static void *xmlMemTraceBlockAt = NULL;
#ifdef MEM_LIST
static MEMHDR *memlist = NULL;
#endif
static void debugmem_tag_error(void *addr);
#ifdef MEM_LIST
static void debugmem_list_add(MEMHDR *);
static void debugmem_list_delete(MEMHDR *);
#endif
#define Mem_Tag_Err(a) debugmem_tag_error(a);
#ifndef TEST_POINT
#define TEST_POINT
#endif
/**
* xmlMallocBreakpoint:
*
* Breakpoint to use in conjunction with xmlMemStopAtBlock. When the block
* number reaches the specified value this function is called. One need to add a breakpoint
* to it to get the context in which the given block is allocated.
*/
void
xmlMallocBreakpoint(void) {
xmlGenericError(xmlGenericErrorContext,
"xmlMallocBreakpoint reached on block %d\n", xmlMemStopAtBlock);
}
/**
* xmlMallocLoc:
* @size: an int specifying the size in byte to allocate.
* @file: the file name or NULL
* @line: the line number
*
* a malloc() equivalent, with logging of the allocation info.
*
* Returns a pointer to the allocated area or NULL in case of lack of memory.
*/
void *
xmlMallocLoc(size_t size, const char * file, int line)
{
MEMHDR *p;
void *ret;
if (!xmlMemInitialized) xmlInitMemory();
#ifdef DEBUG_MEMORY
xmlGenericError(xmlGenericErrorContext,
"Malloc(%d)\n",size);
#endif
TEST_POINT
p = (MEMHDR *) malloc(RESERVE_SIZE+size);
if (!p) {
xmlGenericError(xmlGenericErrorContext,
"xmlMallocLoc : Out of free space\n");
xmlMemoryDump();
return(NULL);
}
p->mh_tag = MEMTAG;
p->mh_size = size;
p->mh_type = MALLOC_TYPE;
p->mh_file = file;
p->mh_line = line;
xmlMutexLock(xmlMemMutex);
p->mh_number = ++block;
debugMemSize += size;
debugMemBlocks++;
if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
#ifdef MEM_LIST
debugmem_list_add(p);
#endif
xmlMutexUnlock(xmlMemMutex);
#ifdef DEBUG_MEMORY
xmlGenericError(xmlGenericErrorContext,
"Malloc(%d) Ok\n",size);
#endif
if (xmlMemStopAtBlock == p->mh_number) xmlMallocBreakpoint();
ret = HDR_2_CLIENT(p);
if (xmlMemTraceBlockAt == ret) {
xmlGenericError(xmlGenericErrorContext,
"%p : Malloc(%d) Ok\n", xmlMemTraceBlockAt, size);
xmlMallocBreakpoint();
}
TEST_POINT
return(ret);
}
/**
* xmlMallocAtomicLoc:
* @size: an int specifying the size in byte to allocate.
* @file: the file name or NULL
* @line: the line number
*
* a malloc() equivalent, with logging of the allocation info.
*
* Returns a pointer to the allocated area or NULL in case of lack of memory.
*/
void *
xmlMallocAtomicLoc(size_t size, const char * file, int line)
{
MEMHDR *p;
void *ret;
if (!xmlMemInitialized) xmlInitMemory();
#ifdef DEBUG_MEMORY
xmlGenericError(xmlGenericErrorContext,
"Malloc(%d)\n",size);
#endif
TEST_POINT
p = (MEMHDR *) malloc(RESERVE_SIZE+size);
if (!p) {
xmlGenericError(xmlGenericErrorContext,
"xmlMallocLoc : Out of free space\n");
xmlMemoryDump();
return(NULL);
}
p->mh_tag = MEMTAG;
p->mh_size = size;
p->mh_type = MALLOC_ATOMIC_TYPE;
p->mh_file = file;
p->mh_line = line;
xmlMutexLock(xmlMemMutex);
p->mh_number = ++block;
debugMemSize += size;
debugMemBlocks++;
if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
#ifdef MEM_LIST
debugmem_list_add(p);
#endif
xmlMutexUnlock(xmlMemMutex);
#ifdef DEBUG_MEMORY
xmlGenericError(xmlGenericErrorContext,
"Malloc(%d) Ok\n",size);
#endif
if (xmlMemStopAtBlock == p->mh_number) xmlMallocBreakpoint();
ret = HDR_2_CLIENT(p);
if (xmlMemTraceBlockAt == ret) {
xmlGenericError(xmlGenericErrorContext,
"%p : Malloc(%d) Ok\n", xmlMemTraceBlockAt, size);
xmlMallocBreakpoint();
}
TEST_POINT
return(ret);
}
/**
* xmlMemMalloc:
* @size: an int specifying the size in byte to allocate.
*
* a malloc() equivalent, with logging of the allocation info.
*
* Returns a pointer to the allocated area or NULL in case of lack of memory.
*/
void *
xmlMemMalloc(size_t size)
{
return(xmlMallocLoc(size, "none", 0));
}
/**
* xmlReallocLoc:
* @ptr: the initial memory block pointer
* @size: an int specifying the size in byte to allocate.
* @file: the file name or NULL
* @line: the line number
*
* a realloc() equivalent, with logging of the allocation info.
*
* 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, int line)
{
MEMHDR *p;
unsigned long number;
#ifdef DEBUG_MEMORY
size_t oldsize;
#endif
if (ptr == NULL)
return(xmlMallocLoc(size, file, line));
if (!xmlMemInitialized) xmlInitMemory();
TEST_POINT
p = CLIENT_2_HDR(ptr);
number = p->mh_number;
if (xmlMemStopAtBlock == number) xmlMallocBreakpoint();
if (p->mh_tag != MEMTAG) {
Mem_Tag_Err(p);
goto error;
}
p->mh_tag = ~MEMTAG;
xmlMutexLock(xmlMemMutex);
debugMemSize -= p->mh_size;
debugMemBlocks--;
#ifdef DEBUG_MEMORY
oldsize = p->mh_size;
#endif
#ifdef MEM_LIST
debugmem_list_delete(p);
#endif
xmlMutexUnlock(xmlMemMutex);
p = (MEMHDR *) realloc(p,RESERVE_SIZE+size);
if (!p) {
goto error;
}
if (xmlMemTraceBlockAt == ptr) {
xmlGenericError(xmlGenericErrorContext,
"%p : Realloced(%d -> %d) Ok\n",
xmlMemTraceBlockAt, p->mh_size, size);
xmlMallocBreakpoint();
}
p->mh_tag = MEMTAG;
p->mh_number = number;
p->mh_type = REALLOC_TYPE;
p->mh_size = size;
p->mh_file = file;
p->mh_line = line;
xmlMutexLock(xmlMemMutex);
debugMemSize += size;
debugMemBlocks++;
if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
#ifdef MEM_LIST
debugmem_list_add(p);
#endif
xmlMutexUnlock(xmlMemMutex);
TEST_POINT
#ifdef DEBUG_MEMORY
xmlGenericError(xmlGenericErrorContext,
"Realloced(%d to %d) Ok\n", oldsize, size);
#endif
return(HDR_2_CLIENT(p));
error:
return(NULL);
}
/**
* xmlMemRealloc:
* @ptr: the initial memory block pointer
* @size: an int specifying the size in byte to allocate.
*
* a realloc() equivalent, with logging of the allocation info.
*
* Returns a pointer to the allocated area or NULL in case of lack of memory.
*/
void *
xmlMemRealloc(void *ptr,size_t size) {
return(xmlReallocLoc(ptr, size, "none", 0));
}
/**
* xmlMemFree:
* @ptr: the memory block pointer
*
* a free() equivalent, with error checking.
*/
void
xmlMemFree(void *ptr)
{
MEMHDR *p;
char *target;
#ifdef DEBUG_MEMORY
size_t size;
#endif
if (ptr == (void *) -1) {
xmlGenericError(xmlGenericErrorContext,
"trying to free pointer from freed area\n");
goto error;
}
if (xmlMemTraceBlockAt == ptr) {
xmlGenericError(xmlGenericErrorContext,
"%p : Freed()\n", xmlMemTraceBlockAt);
xmlMallocBreakpoint();
}
TEST_POINT
target = (char *) ptr;
p = CLIENT_2_HDR(ptr);
if (p->mh_tag != MEMTAG) {
Mem_Tag_Err(p);
goto error;
}
if (xmlMemStopAtBlock == p->mh_number) xmlMallocBreakpoint();
p->mh_tag = ~MEMTAG;
memset(target, -1, p->mh_size);
xmlMutexLock(xmlMemMutex);
debugMemSize -= p->mh_size;
debugMemBlocks--;
#ifdef DEBUG_MEMORY
size = p->mh_size;
#endif
#ifdef MEM_LIST
debugmem_list_delete(p);
#endif
xmlMutexUnlock(xmlMemMutex);
free(p);
TEST_POINT
#ifdef DEBUG_MEMORY
xmlGenericError(xmlGenericErrorContext,
"Freed(%d) Ok\n", size);
#endif
return;
error:
xmlGenericError(xmlGenericErrorContext,
"xmlMemFree(%lX) error\n", (unsigned long) ptr);
xmlMallocBreakpoint();
return;
}
/**
* xmlMemStrdupLoc:
* @str: the initial string pointer
* @file: the file name or NULL
* @line: the line number
*
* a strdup() equivalent, with logging of the allocation info.
*
* Returns a pointer to the new string or NULL if allocation error occurred.
*/
char *
xmlMemStrdupLoc(const char *str, const char *file, int line)
{
char *s;
size_t size = strlen(str) + 1;
MEMHDR *p;
if (!xmlMemInitialized) xmlInitMemory();
TEST_POINT
p = (MEMHDR *) malloc(RESERVE_SIZE+size);
if (!p) {
goto error;
}
p->mh_tag = MEMTAG;
p->mh_size = size;
p->mh_type = STRDUP_TYPE;
p->mh_file = file;
p->mh_line = line;
xmlMutexLock(xmlMemMutex);
p->mh_number = ++block;
debugMemSize += size;
debugMemBlocks++;
if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
#ifdef MEM_LIST
debugmem_list_add(p);
#endif
xmlMutexUnlock(xmlMemMutex);
s = (char *) HDR_2_CLIENT(p);
if (xmlMemStopAtBlock == p->mh_number) xmlMallocBreakpoint();
if (s != NULL)
strcpy(s,str);
else
goto error;
TEST_POINT
if (xmlMemTraceBlockAt == s) {
xmlGenericError(xmlGenericErrorContext,
"%p : Strdup() Ok\n", xmlMemTraceBlockAt);
xmlMallocBreakpoint();
}
return(s);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -