/*
* xmlmemory.c: libxml memory allocator wrapper.
*
* daniel@veillard.com
*/
#define IN_LIBXML
#include "libxml.h"
#include <string.h>
#ifdef HAVE_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
#endif
#endif
#include <libxml/xmlmemory.h>
#include <libxml/xmlerror.h>
static int xmlMemInitialized = 0;
static unsigned long debugMemSize = 0;
static unsigned long debugMemBlocks = 0;
static unsigned long debugMaxMemSize = 0;
void xmlMallocBreakpoint(void);
/************************************************************************
* *
* Macros, variables and associated types *
* *
************************************************************************/
#if !defined(LIBXML_THREAD_ENABLED) && !defined(LIBXML_THREAD_ALLOC_ENABLED)
#ifdef xmlMalloc
#endif
#ifdef xmlRealloc
#endif
#ifdef xmlMemStrdup
#endif
#endif
/*
* Each of the blocks allocated begin with a header containing informations
*/
typedef struct memnod {
unsigned int mh_tag;
unsigned int mh_type;
unsigned long mh_number;
#ifdef MEM_LIST
#endif
const char *mh_file;
unsigned int mh_line;
} MEMHDR;
#ifdef SUN4
#else
#define ALIGN_SIZE sizeof(double)
#endif
/ ALIGN_SIZE ) * ALIGN_SIZE)
static unsigned int block=0;
static unsigned int xmlMemStopAtBlock = 0;
#ifdef MEM_LIST
#endif
static void debugmem_tag_error(void *addr);
#ifdef MEM_LIST
static void debugmem_list_add(MEMHDR *);
static void debugmem_list_delete(MEMHDR *);
#endif
#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) {
"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 *
{
MEMHDR *p;
void *ret;
if (!xmlMemInitialized) xmlInitMemory();
#ifdef DEBUG_MEMORY
"Malloc(%d)\n",size);
#endif
if (!p) {
"xmlMallocLoc : Out of free space\n");
return(NULL);
}
p->mh_type = MALLOC_TYPE;
debugMemSize += size;
#ifdef MEM_LIST
#endif
#ifdef DEBUG_MEMORY
"Malloc(%d) Ok\n",size);
#endif
ret = HDR_2_CLIENT(p);
if (xmlMemTraceBlockAt == ret) {
}
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 *
{
MEMHDR *p;
void *ret;
if (!xmlMemInitialized) xmlInitMemory();
#ifdef DEBUG_MEMORY
"Malloc(%d)\n",size);
#endif
if (!p) {
"xmlMallocLoc : Out of free space\n");
return(NULL);
}
p->mh_type = MALLOC_ATOMIC_TYPE;
debugMemSize += size;
#ifdef MEM_LIST
#endif
#ifdef DEBUG_MEMORY
"Malloc(%d) Ok\n",size);
#endif
ret = HDR_2_CLIENT(p);
if (xmlMemTraceBlockAt == ret) {
}
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 *
{
}
/**
* 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 *
{
MEMHDR *p;
unsigned long number;
#ifdef DEBUG_MEMORY
#endif
if (!xmlMemInitialized) xmlInitMemory();
p = CLIENT_2_HDR(ptr);
Mem_Tag_Err(p);
goto error;
}
debugMemSize -= p->mh_size;
#ifdef DEBUG_MEMORY
#endif
#ifdef MEM_LIST
#endif
if (!p) {
goto error;
}
if (xmlMemTraceBlockAt == ptr) {
"%p : Realloced(%d -> %d) Ok\n",
}
p->mh_type = REALLOC_TYPE;
debugMemSize += size;
#ifdef MEM_LIST
#endif
#ifdef DEBUG_MEMORY
#endif
return(HDR_2_CLIENT(p));
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 *
}
/**
* xmlMemFree:
* @ptr: the memory block pointer
*
* a free() equivalent, with error checking.
*/
void
{
MEMHDR *p;
char *target;
#ifdef DEBUG_MEMORY
#endif
return;
if (ptr == (void *) -1) {
"trying to free pointer from freed area\n");
goto error;
}
if (xmlMemTraceBlockAt == ptr) {
"%p : Freed()\n", xmlMemTraceBlockAt);
}
p = CLIENT_2_HDR(ptr);
Mem_Tag_Err(p);
goto error;
}
debugMemSize -= p->mh_size;
#ifdef DEBUG_MEMORY
#endif
#ifdef MEM_LIST
#endif
free(p);
#ifdef DEBUG_MEMORY
"Freed(%d) Ok\n", size);
#endif
return;
"xmlMemFree(%lX) error\n", (unsigned long) ptr);
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 *
{
char *s;
MEMHDR *p;
if (!xmlMemInitialized) xmlInitMemory();
if (!p) {
goto error;
}
p->mh_type = STRDUP_TYPE;
debugMemSize += size;
#ifdef MEM_LIST
#endif
s = (char *) HDR_2_CLIENT(p);
if (s != NULL)
else
goto error;
if (xmlMemTraceBlockAt == s) {
"%p : Strdup() Ok\n", xmlMemTraceBlockAt);
}
return(s);
return(NULL);
}
/**
* xmlMemoryStrdup:
* @str: the initial string pointer
*
* a strdup() equivalent, with logging of the allocation info.
*
* Returns a pointer to the new string or NULL if allocation error occurred.
*/
char *
}
/**
* xmlMemUsed:
*
* Provides the amount of memory currently allocated
*
* Returns an int representing the amount of memory allocated.
*/
int
xmlMemUsed(void) {
return(debugMemSize);
}
/**
* xmlMemBlocks:
*
* Provides the number of memory areas currently allocated
*
* Returns an int representing the number of blocks
*/
int
xmlMemBlocks(void) {
return(debugMemBlocks);
}
#ifdef MEM_LIST
/**
* xmlMemContentShow:
* @fp: a FILE descriptor used as the output file
* @p: a memory block header
*
* tries to show some content from the memory block
*/
static void
{
if (p == NULL) {
return;
}
for (i = 0;i < len;i++) {
if (buf[i] == 0) break;
}
if ((i < 4) && ((buf[i] != 0) || (i == 0))) {
if (len >= 4) {
MEMHDR *q;
void *cur;
q = CLIENT_2_HDR(cur);
p = memlist;
k = 0;
while (p != NULL) {
if (p == q) break;
p = p->mh_next;
if (k++ > 100) break;
}
if ((p != NULL) && (p == q)) {
p->mh_number, j);
return;
}
}
}
} else if ((i == 0) && (buf[i] == 0)) {
} else {
else {
for (j = 0;j < i;j++)
}
}
}
#endif
/**
* xmlMemDisplay:
* @fp: a FILE descriptor used as the output file, if NULL, the result is
* written to the file .memorylist
*
* show in-extenso the memory blocks allocated
*/
void
{
#ifdef MEM_LIST
MEMHDR *p;
unsigned idx;
int nb = 0;
#if defined(HAVE_LOCALTIME) && defined(HAVE_STRFTIME)
#endif
#endif
return;
}
#ifdef MEM_LIST
#if defined(HAVE_LOCALTIME) && defined(HAVE_STRFTIME)
#endif
idx = 0;
p = memlist;
while (p) {
(unsigned long)p->mh_size);
switch (p->mh_type) {
default:
return;
}
nb++;
if (nb < 100)
xmlMemContentShow(fp, p);
else
p = p->mh_next;
}
#else
#endif
}
#ifdef MEM_LIST
{
memlist = p;
#ifdef MEM_LIST_DEBUG
if (stderr)
#endif
}
{
if (p->mh_next)
if (p->mh_prev)
#ifdef MEM_LIST_DEBUG
if (stderr)
#endif
}
#endif
/*
* debugmem_tag_error:
*
* internal error function.
*/
static void debugmem_tag_error(void *p)
{
"Memory tag error occurs :%p \n\t bye\n", p);
#ifdef MEM_LIST
if (stderr)
#endif
}
#ifdef MEM_LIST
#endif
/**
* xmlMemShow:
* @fp: a FILE descriptor used as the output file
* @nr: number of entries to dump
*
* show a show display of the memory allocated, and dump
* the @nr last allocated areas which were not freed
*/
void
{
#ifdef MEM_LIST
MEMHDR *p;
#endif
#ifdef MEM_LIST
if (nr > 0) {
p = memlist;
while ((p) && nr > 0) {
switch (p->mh_type) {
}
xmlMemContentShow(fp, p);
nr--;
p = p->mh_next;
}
}
#endif /* MEM_LIST */
}
/**
* xmlMemoryDump:
*
* Dump in-extenso the memory blocks allocated to the file .memorylist
*/
void
xmlMemoryDump(void)
{
#ifdef MEM_LIST
if (debugMaxMemSize == 0)
return;
else xmlMemoryDumpFile = dump;
#endif /* MEM_LIST */
}
/****************************************************************
* *
* Initialization Routines *
* *
****************************************************************/
/**
* xmlInitMemory:
*
* Initialize the memory layer.
*
* Returns 0 on success
*/
int
xmlInitMemory(void)
{
#ifdef HAVE_STDLIB_H
char *breakpoint;
#endif
#ifdef DEBUG_MEMORY
"xmlInitMemory()\n");
#endif
/*
This is really not good code (see Bug 130419). Suggestions for
improvement will be welcome!
*/
if (xmlMemInitialized) return(-1);
xmlMemInitialized = 1;
xmlMemMutex = xmlNewMutex();
#ifdef HAVE_STDLIB_H
if (breakpoint != NULL) {
}
#endif
#ifdef HAVE_STDLIB_H
if (breakpoint != NULL) {
}
#endif
#ifdef DEBUG_MEMORY
"xmlInitMemory() Ok\n");
#endif
return(0);
}
/**
* xmlCleanupMemory:
*
* Free up all the memory allocated by the library for its own
* use. This should not be called by user level code.
*/
void
xmlCleanupMemory(void) {
#ifdef DEBUG_MEMORY
"xmlCleanupMemory()\n");
#endif
if (xmlMemInitialized == 0)
return;
xmlMemMutex = NULL;
xmlMemInitialized = 0;
#ifdef DEBUG_MEMORY
"xmlCleanupMemory() Ok\n");
#endif
}
/**
* xmlMemSetup:
* @freeFunc: the free() function to use
* @mallocFunc: the malloc() function to use
* @reallocFunc: the realloc() function to use
* @strdupFunc: the strdup() function to use
*
* 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 ?
*
* Returns 0 on success
*/
int
#ifdef DEBUG_MEMORY
"xmlMemSetup()\n");
#endif
return(-1);
if (mallocFunc == NULL)
return(-1);
if (reallocFunc == NULL)
return(-1);
if (strdupFunc == NULL)
return(-1);
#ifdef DEBUG_MEMORY
"xmlMemSetup() Ok\n");
#endif
return(0);
}
/**
* xmlMemGet:
* @freeFunc: place to save the free() function in use
* @mallocFunc: place to save the malloc() function in use
* @reallocFunc: place to save the realloc() function in use
* @strdupFunc: place to save the strdup() function in use
*
* Provides the memory access functions set currently in use
*
* Returns 0 on success
*/
int
return(0);
}
/**
* xmlGcMemSetup:
* @freeFunc: the free() function to use
* @mallocFunc: the malloc() function to use
* @mallocAtomicFunc: the malloc() function to use for atomic allocations
* @reallocFunc: the realloc() function to use
* @strdupFunc: the strdup() function to use
*
* 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
*
* Should this be blocked if there was already some allocations
* done ?
*
* Returns 0 on success
*/
int
#ifdef DEBUG_MEMORY
"xmlGcMemSetup()\n");
#endif
return(-1);
if (mallocFunc == NULL)
return(-1);
if (mallocAtomicFunc == NULL)
return(-1);
if (reallocFunc == NULL)
return(-1);
if (strdupFunc == NULL)
return(-1);
#ifdef DEBUG_MEMORY
"xmlGcMemSetup() Ok\n");
#endif
return(0);
}
/**
* xmlGcMemGet:
* @freeFunc: place to save the free() function in use
* @mallocFunc: place to save the malloc() function in use
* @mallocAtomicFunc: place to save the atomic malloc() function in use
* @reallocFunc: place to save the realloc() function in use
* @strdupFunc: place to save the strdup() function in use
*
* 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
*
* Returns 0 on success
*/
int
return(0);
}
#define bottom_xmlmemory
#include "elfgcchack.h"