blob: d547e2ce21687d19051288fa783233bf861fc328 [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
Daniel Veillard26908ab2002-01-01 16:50:03 +00002 * xmlmemory.c: libxml memory allocator wrapper.
Owen Taylor3473f882001-02-23 17:55:21 +00003 *
Daniel Veillardc5d64342001-06-24 12:13:24 +00004 * daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +00005 */
6
Daniel Veillard34ce8be2002-03-18 19:37:11 +00007#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +00008#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +00009
Owen Taylor3473f882001-02-23 17:55:21 +000010#include <string.h>
11
12#ifdef HAVE_SYS_TYPES_H
13#include <sys/types.h>
14#endif
Daniel Veillard0ba59232002-02-10 13:20:39 +000015
Owen Taylor3473f882001-02-23 17:55:21 +000016#ifdef HAVE_TIME_H
17#include <time.h>
18#endif
Daniel Veillard0ba59232002-02-10 13:20:39 +000019
20#ifdef HAVE_STDLIB_H
21#include <stdlib.h>
22#else
Owen Taylor3473f882001-02-23 17:55:21 +000023#ifdef HAVE_MALLOC_H
24#include <malloc.h>
25#endif
Owen Taylor3473f882001-02-23 17:55:21 +000026#endif
Daniel Veillard0ba59232002-02-10 13:20:39 +000027
Owen Taylor3473f882001-02-23 17:55:21 +000028#ifdef HAVE_CTYPE_H
29#include <ctype.h>
30#endif
31
Daniel Veillardf93a8662004-07-01 12:56:30 +000032/* #define DEBUG_MEMORY */
Daniel Veillard4432df22003-09-28 18:58:27 +000033
Daniel Veillard70cab352002-02-06 16:06:58 +000034/**
35 * MEM_LIST:
36 *
37 * keep track of all allocated blocks for error reporting
38 * Always build the memory list !
39 */
Daniel Veillardc064b472003-09-29 10:55:05 +000040#ifdef DEBUG_MEMORY_LOCATION
Daniel Veillard70cab352002-02-06 16:06:58 +000041#ifndef MEM_LIST
42#define MEM_LIST /* keep a list of all the allocated memory blocks */
43#endif
Daniel Veillardc064b472003-09-29 10:55:05 +000044#endif
Owen Taylor3473f882001-02-23 17:55:21 +000045
William M. Brack5ab479b2004-06-10 13:00:15 +000046#include <libxml/globals.h> /* must come before xmlmemory.h */
Owen Taylor3473f882001-02-23 17:55:21 +000047#include <libxml/xmlmemory.h>
48#include <libxml/xmlerror.h>
William M. Brack0622fe82003-11-29 10:47:56 +000049#include <libxml/threads.h>
Owen Taylor3473f882001-02-23 17:55:21 +000050
Daniel Veillard4432df22003-09-28 18:58:27 +000051static int xmlMemInitialized = 0;
Daniel Veillardfb43bd62003-09-29 09:22:39 +000052static unsigned long debugMemSize = 0;
Daniel Veillard36e5cd52004-11-02 14:52:23 +000053static unsigned long debugMemBlocks = 0;
Daniel Veillardfb43bd62003-09-29 09:22:39 +000054static unsigned long debugMaxMemSize = 0;
William M. Brack0622fe82003-11-29 10:47:56 +000055static xmlMutexPtr xmlMemMutex = NULL;
Daniel Veillard4432df22003-09-28 18:58:27 +000056
Daniel Veillard56a4cb82001-03-24 17:00:36 +000057void xmlMallocBreakpoint(void);
Daniel Veillard56a4cb82001-03-24 17:00:36 +000058
59/************************************************************************
60 * *
61 * Macros, variables and associated types *
62 * *
63 ************************************************************************/
64
William M. Brack5ab479b2004-06-10 13:00:15 +000065#if !defined(LIBXML_THREAD_ENABLED) && !defined(LIBXML_THREAD_ALLOC_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +000066#ifdef xmlMalloc
67#undef xmlMalloc
68#endif
69#ifdef xmlRealloc
70#undef xmlRealloc
71#endif
72#ifdef xmlMemStrdup
73#undef xmlMemStrdup
74#endif
William M. Brack5ab479b2004-06-10 13:00:15 +000075#endif
Owen Taylor3473f882001-02-23 17:55:21 +000076
77/*
78 * Each of the blocks allocated begin with a header containing informations
79 */
80
81#define MEMTAG 0x5aa5
82
83#define MALLOC_TYPE 1
84#define REALLOC_TYPE 2
85#define STRDUP_TYPE 3
Daniel Veillard3c908dc2003-04-19 00:07:51 +000086#define MALLOC_ATOMIC_TYPE 4
87#define REALLOC_ATOMIC_TYPE 5
Owen Taylor3473f882001-02-23 17:55:21 +000088
89typedef struct memnod {
90 unsigned int mh_tag;
91 unsigned int mh_type;
92 unsigned long mh_number;
93 size_t mh_size;
94#ifdef MEM_LIST
95 struct memnod *mh_next;
96 struct memnod *mh_prev;
97#endif
98 const char *mh_file;
99 unsigned int mh_line;
100} MEMHDR;
101
102
103#ifdef SUN4
104#define ALIGN_SIZE 16
105#else
106#define ALIGN_SIZE sizeof(double)
107#endif
108#define HDR_SIZE sizeof(MEMHDR)
109#define RESERVE_SIZE (((HDR_SIZE + (ALIGN_SIZE-1)) \
110 / ALIGN_SIZE ) * ALIGN_SIZE)
111
112
113#define CLIENT_2_HDR(a) ((MEMHDR *) (((char *) (a)) - RESERVE_SIZE))
114#define HDR_2_CLIENT(a) ((void *) (((char *) (a)) + RESERVE_SIZE))
115
116
William M. Brack0622fe82003-11-29 10:47:56 +0000117static unsigned int block=0;
118static unsigned int xmlMemStopAtBlock = 0;
Daniel Veillardb44025c2001-10-11 22:55:55 +0000119static void *xmlMemTraceBlockAt = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +0000120#ifdef MEM_LIST
121static MEMHDR *memlist = NULL;
122#endif
123
Daniel Veillard01c13b52002-12-10 15:19:08 +0000124static void debugmem_tag_error(void *addr);
Owen Taylor3473f882001-02-23 17:55:21 +0000125#ifdef MEM_LIST
Daniel Veillard01c13b52002-12-10 15:19:08 +0000126static void debugmem_list_add(MEMHDR *);
127static void debugmem_list_delete(MEMHDR *);
Owen Taylor3473f882001-02-23 17:55:21 +0000128#endif
129#define Mem_Tag_Err(a) debugmem_tag_error(a);
130
131#ifndef TEST_POINT
132#define TEST_POINT
133#endif
134
135/**
136 * xmlMallocBreakpoint:
137 *
138 * Breakpoint to use in conjunction with xmlMemStopAtBlock. When the block
139 * number reaches the specified value this function is called. One need to add a breakpoint
140 * to it to get the context in which the given block is allocated.
141 */
142
143void
144xmlMallocBreakpoint(void) {
145 xmlGenericError(xmlGenericErrorContext,
146 "xmlMallocBreakpoint reached on block %d\n", xmlMemStopAtBlock);
147}
148
149/**
150 * xmlMallocLoc:
151 * @size: an int specifying the size in byte to allocate.
152 * @file: the file name or NULL
153 * @line: the line number
154 *
155 * a malloc() equivalent, with logging of the allocation info.
156 *
157 * Returns a pointer to the allocated area or NULL in case of lack of memory.
158 */
159
160void *
Daniel Veillard8599e702001-07-17 21:38:51 +0000161xmlMallocLoc(size_t size, const char * file, int line)
Owen Taylor3473f882001-02-23 17:55:21 +0000162{
163 MEMHDR *p;
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000164 void *ret;
Owen Taylor3473f882001-02-23 17:55:21 +0000165
166 if (!xmlMemInitialized) xmlInitMemory();
167#ifdef DEBUG_MEMORY
168 xmlGenericError(xmlGenericErrorContext,
169 "Malloc(%d)\n",size);
170#endif
171
172 TEST_POINT
173
174 p = (MEMHDR *) malloc(RESERVE_SIZE+size);
175
176 if (!p) {
177 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard26908ab2002-01-01 16:50:03 +0000178 "xmlMallocLoc : Out of free space\n");
Owen Taylor3473f882001-02-23 17:55:21 +0000179 xmlMemoryDump();
180 return(NULL);
181 }
182 p->mh_tag = MEMTAG;
Owen Taylor3473f882001-02-23 17:55:21 +0000183 p->mh_size = size;
184 p->mh_type = MALLOC_TYPE;
185 p->mh_file = file;
186 p->mh_line = line;
William M. Brack0622fe82003-11-29 10:47:56 +0000187 xmlMutexLock(xmlMemMutex);
188 p->mh_number = ++block;
Owen Taylor3473f882001-02-23 17:55:21 +0000189 debugMemSize += size;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000190 debugMemBlocks++;
Owen Taylor3473f882001-02-23 17:55:21 +0000191 if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
192#ifdef MEM_LIST
193 debugmem_list_add(p);
194#endif
William M. Brack0622fe82003-11-29 10:47:56 +0000195 xmlMutexUnlock(xmlMemMutex);
196
Owen Taylor3473f882001-02-23 17:55:21 +0000197#ifdef DEBUG_MEMORY
198 xmlGenericError(xmlGenericErrorContext,
199 "Malloc(%d) Ok\n",size);
200#endif
201
William M. Brack0622fe82003-11-29 10:47:56 +0000202 if (xmlMemStopAtBlock == p->mh_number) xmlMallocBreakpoint();
Owen Taylor3473f882001-02-23 17:55:21 +0000203
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000204 ret = HDR_2_CLIENT(p);
205
206 if (xmlMemTraceBlockAt == ret) {
207 xmlGenericError(xmlGenericErrorContext,
208 "%p : Malloc(%d) Ok\n", xmlMemTraceBlockAt, size);
209 xmlMallocBreakpoint();
210 }
211
Owen Taylor3473f882001-02-23 17:55:21 +0000212 TEST_POINT
213
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000214 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000215}
216
217/**
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000218 * xmlMallocAtomicLoc:
219 * @size: an int specifying the size in byte to allocate.
220 * @file: the file name or NULL
221 * @line: the line number
222 *
223 * a malloc() equivalent, with logging of the allocation info.
224 *
225 * Returns a pointer to the allocated area or NULL in case of lack of memory.
226 */
227
228void *
229xmlMallocAtomicLoc(size_t size, const char * file, int line)
230{
231 MEMHDR *p;
232 void *ret;
233
234 if (!xmlMemInitialized) xmlInitMemory();
235#ifdef DEBUG_MEMORY
236 xmlGenericError(xmlGenericErrorContext,
237 "Malloc(%d)\n",size);
238#endif
239
240 TEST_POINT
241
242 p = (MEMHDR *) malloc(RESERVE_SIZE+size);
243
244 if (!p) {
245 xmlGenericError(xmlGenericErrorContext,
246 "xmlMallocLoc : Out of free space\n");
247 xmlMemoryDump();
248 return(NULL);
249 }
250 p->mh_tag = MEMTAG;
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000251 p->mh_size = size;
252 p->mh_type = MALLOC_ATOMIC_TYPE;
253 p->mh_file = file;
254 p->mh_line = line;
William M. Brack0622fe82003-11-29 10:47:56 +0000255 xmlMutexLock(xmlMemMutex);
256 p->mh_number = ++block;
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000257 debugMemSize += size;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000258 debugMemBlocks++;
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000259 if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
260#ifdef MEM_LIST
261 debugmem_list_add(p);
262#endif
William M. Brack0622fe82003-11-29 10:47:56 +0000263 xmlMutexUnlock(xmlMemMutex);
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000264
265#ifdef DEBUG_MEMORY
266 xmlGenericError(xmlGenericErrorContext,
267 "Malloc(%d) Ok\n",size);
268#endif
269
William M. Brack0622fe82003-11-29 10:47:56 +0000270 if (xmlMemStopAtBlock == p->mh_number) xmlMallocBreakpoint();
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000271
272 ret = HDR_2_CLIENT(p);
273
274 if (xmlMemTraceBlockAt == ret) {
275 xmlGenericError(xmlGenericErrorContext,
276 "%p : Malloc(%d) Ok\n", xmlMemTraceBlockAt, size);
277 xmlMallocBreakpoint();
278 }
279
280 TEST_POINT
281
282 return(ret);
283}
284/**
Owen Taylor3473f882001-02-23 17:55:21 +0000285 * xmlMemMalloc:
286 * @size: an int specifying the size in byte to allocate.
287 *
288 * a malloc() equivalent, with logging of the allocation info.
289 *
290 * Returns a pointer to the allocated area or NULL in case of lack of memory.
291 */
292
293void *
Daniel Veillard8599e702001-07-17 21:38:51 +0000294xmlMemMalloc(size_t size)
Owen Taylor3473f882001-02-23 17:55:21 +0000295{
296 return(xmlMallocLoc(size, "none", 0));
297}
298
299/**
300 * xmlReallocLoc:
301 * @ptr: the initial memory block pointer
302 * @size: an int specifying the size in byte to allocate.
303 * @file: the file name or NULL
304 * @line: the line number
305 *
306 * a realloc() equivalent, with logging of the allocation info.
307 *
308 * Returns a pointer to the allocated area or NULL in case of lack of memory.
309 */
310
311void *
Daniel Veillard8599e702001-07-17 21:38:51 +0000312xmlReallocLoc(void *ptr,size_t size, const char * file, int line)
Owen Taylor3473f882001-02-23 17:55:21 +0000313{
314 MEMHDR *p;
315 unsigned long number;
Daniel Veillard529233c2004-07-02 12:23:44 +0000316#ifdef DEBUG_MEMORY
317 size_t oldsize;
318#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000319
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000320 if (ptr == NULL)
Aleksey Sanine9f08112004-01-22 22:20:31 +0000321 return(xmlMallocLoc(size, file, line));
322
323 if (!xmlMemInitialized) xmlInitMemory();
Owen Taylor3473f882001-02-23 17:55:21 +0000324 TEST_POINT
325
326 p = CLIENT_2_HDR(ptr);
327 number = p->mh_number;
328 if (p->mh_tag != MEMTAG) {
329 Mem_Tag_Err(p);
330 goto error;
331 }
332 p->mh_tag = ~MEMTAG;
William M. Brack0622fe82003-11-29 10:47:56 +0000333 xmlMutexLock(xmlMemMutex);
Owen Taylor3473f882001-02-23 17:55:21 +0000334 debugMemSize -= p->mh_size;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000335 debugMemBlocks--;
Daniel Veillard529233c2004-07-02 12:23:44 +0000336#ifdef DEBUG_MEMORY
337 oldsize = p->mh_size;
338#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000339#ifdef MEM_LIST
340 debugmem_list_delete(p);
341#endif
William M. Brack0622fe82003-11-29 10:47:56 +0000342 xmlMutexUnlock(xmlMemMutex);
343
Owen Taylor3473f882001-02-23 17:55:21 +0000344 p = (MEMHDR *) realloc(p,RESERVE_SIZE+size);
345 if (!p) {
346 goto error;
347 }
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000348 if (xmlMemTraceBlockAt == ptr) {
349 xmlGenericError(xmlGenericErrorContext,
350 "%p : Realloced(%d -> %d) Ok\n",
351 xmlMemTraceBlockAt, p->mh_size, size);
352 xmlMallocBreakpoint();
353 }
Owen Taylor3473f882001-02-23 17:55:21 +0000354 p->mh_tag = MEMTAG;
355 p->mh_number = number;
356 p->mh_type = REALLOC_TYPE;
357 p->mh_size = size;
358 p->mh_file = file;
359 p->mh_line = line;
William M. Brack0622fe82003-11-29 10:47:56 +0000360 xmlMutexLock(xmlMemMutex);
Owen Taylor3473f882001-02-23 17:55:21 +0000361 debugMemSize += size;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000362 debugMemBlocks++;
Owen Taylor3473f882001-02-23 17:55:21 +0000363 if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
364#ifdef MEM_LIST
365 debugmem_list_add(p);
366#endif
William M. Brack0622fe82003-11-29 10:47:56 +0000367 xmlMutexUnlock(xmlMemMutex);
Owen Taylor3473f882001-02-23 17:55:21 +0000368
369 TEST_POINT
370
Daniel Veillard529233c2004-07-02 12:23:44 +0000371#ifdef DEBUG_MEMORY
372 xmlGenericError(xmlGenericErrorContext,
373 "Realloced(%d to %d) Ok\n", oldsize, size);
374#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000375 return(HDR_2_CLIENT(p));
376
377error:
378 return(NULL);
379}
380
381/**
382 * xmlMemRealloc:
383 * @ptr: the initial memory block pointer
384 * @size: an int specifying the size in byte to allocate.
385 *
386 * a realloc() equivalent, with logging of the allocation info.
387 *
388 * Returns a pointer to the allocated area or NULL in case of lack of memory.
389 */
390
391void *
Daniel Veillard8599e702001-07-17 21:38:51 +0000392xmlMemRealloc(void *ptr,size_t size) {
Owen Taylor3473f882001-02-23 17:55:21 +0000393 return(xmlReallocLoc(ptr, size, "none", 0));
394}
395
396/**
397 * xmlMemFree:
398 * @ptr: the memory block pointer
399 *
400 * a free() equivalent, with error checking.
401 */
402void
403xmlMemFree(void *ptr)
404{
405 MEMHDR *p;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000406 char *target;
Daniel Veillard529233c2004-07-02 12:23:44 +0000407#ifdef DEBUG_MEMORY
408 size_t size;
409#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000410
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000411 if (ptr == (void *) -1) {
412 xmlGenericError(xmlGenericErrorContext,
413 "trying to free pointer from freed area\n");
414 goto error;
415 }
416
417 if (xmlMemTraceBlockAt == ptr) {
418 xmlGenericError(xmlGenericErrorContext,
419 "%p : Freed()\n", xmlMemTraceBlockAt);
420 xmlMallocBreakpoint();
421 }
422
Owen Taylor3473f882001-02-23 17:55:21 +0000423 TEST_POINT
424
Daniel Veillard92ad2102001-03-27 12:47:33 +0000425 target = (char *) ptr;
426
Owen Taylor3473f882001-02-23 17:55:21 +0000427 p = CLIENT_2_HDR(ptr);
428 if (p->mh_tag != MEMTAG) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000429 Mem_Tag_Err(p);
430 goto error;
Owen Taylor3473f882001-02-23 17:55:21 +0000431 }
432 p->mh_tag = ~MEMTAG;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000433 memset(target, -1, p->mh_size);
William M. Brack0622fe82003-11-29 10:47:56 +0000434 xmlMutexLock(xmlMemMutex);
435 debugMemSize -= p->mh_size;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000436 debugMemBlocks--;
Daniel Veillard529233c2004-07-02 12:23:44 +0000437#ifdef DEBUG_MEMORY
438 size = p->mh_size;
439#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000440#ifdef MEM_LIST
441 debugmem_list_delete(p);
442#endif
William M. Brack0622fe82003-11-29 10:47:56 +0000443 xmlMutexUnlock(xmlMemMutex);
444
Owen Taylor3473f882001-02-23 17:55:21 +0000445 free(p);
446
447 TEST_POINT
448
Daniel Veillard529233c2004-07-02 12:23:44 +0000449#ifdef DEBUG_MEMORY
450 xmlGenericError(xmlGenericErrorContext,
451 "Freed(%d) Ok\n", size);
452#endif
453
Owen Taylor3473f882001-02-23 17:55:21 +0000454 return;
455
456error:
457 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard26908ab2002-01-01 16:50:03 +0000458 "xmlMemFree(%lX) error\n", (unsigned long) ptr);
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000459 xmlMallocBreakpoint();
Owen Taylor3473f882001-02-23 17:55:21 +0000460 return;
461}
462
463/**
464 * xmlMemStrdupLoc:
Daniel Veillard9d06d302002-01-22 18:15:52 +0000465 * @str: the initial string pointer
Owen Taylor3473f882001-02-23 17:55:21 +0000466 * @file: the file name or NULL
467 * @line: the line number
468 *
469 * a strdup() equivalent, with logging of the allocation info.
470 *
Daniel Veillard26908ab2002-01-01 16:50:03 +0000471 * Returns a pointer to the new string or NULL if allocation error occurred.
Owen Taylor3473f882001-02-23 17:55:21 +0000472 */
473
474char *
475xmlMemStrdupLoc(const char *str, const char *file, int line)
476{
477 char *s;
478 size_t size = strlen(str) + 1;
479 MEMHDR *p;
480
481 if (!xmlMemInitialized) xmlInitMemory();
482 TEST_POINT
483
484 p = (MEMHDR *) malloc(RESERVE_SIZE+size);
485 if (!p) {
486 goto error;
487 }
488 p->mh_tag = MEMTAG;
Owen Taylor3473f882001-02-23 17:55:21 +0000489 p->mh_size = size;
490 p->mh_type = STRDUP_TYPE;
491 p->mh_file = file;
492 p->mh_line = line;
William M. Brack0622fe82003-11-29 10:47:56 +0000493 xmlMutexLock(xmlMemMutex);
494 p->mh_number = ++block;
Owen Taylor3473f882001-02-23 17:55:21 +0000495 debugMemSize += size;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000496 debugMemBlocks++;
Owen Taylor3473f882001-02-23 17:55:21 +0000497 if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
498#ifdef MEM_LIST
499 debugmem_list_add(p);
500#endif
William M. Brack0622fe82003-11-29 10:47:56 +0000501 xmlMutexUnlock(xmlMemMutex);
502
Owen Taylor3473f882001-02-23 17:55:21 +0000503 s = (char *) HDR_2_CLIENT(p);
504
William M. Brack0622fe82003-11-29 10:47:56 +0000505 if (xmlMemStopAtBlock == p->mh_number) xmlMallocBreakpoint();
Owen Taylor3473f882001-02-23 17:55:21 +0000506
507 if (s != NULL)
508 strcpy(s,str);
509 else
510 goto error;
511
512 TEST_POINT
513
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000514 if (xmlMemTraceBlockAt == s) {
515 xmlGenericError(xmlGenericErrorContext,
516 "%p : Strdup() Ok\n", xmlMemTraceBlockAt);
517 xmlMallocBreakpoint();
518 }
519
Owen Taylor3473f882001-02-23 17:55:21 +0000520 return(s);
521
522error:
523 return(NULL);
524}
525
526/**
527 * xmlMemoryStrdup:
Daniel Veillard01c13b52002-12-10 15:19:08 +0000528 * @str: the initial string pointer
Owen Taylor3473f882001-02-23 17:55:21 +0000529 *
530 * a strdup() equivalent, with logging of the allocation info.
531 *
Daniel Veillard26908ab2002-01-01 16:50:03 +0000532 * Returns a pointer to the new string or NULL if allocation error occurred.
Owen Taylor3473f882001-02-23 17:55:21 +0000533 */
534
535char *
536xmlMemoryStrdup(const char *str) {
537 return(xmlMemStrdupLoc(str, "none", 0));
538}
539
540/**
541 * xmlMemUsed:
542 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000543 * Provides the amount of memory currently allocated
Owen Taylor3473f882001-02-23 17:55:21 +0000544 *
545 * Returns an int representing the amount of memory allocated.
546 */
547
548int
549xmlMemUsed(void) {
550 return(debugMemSize);
551}
552
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000553/**
554 * xmlMemBlocks:
555 *
556 * Provides the number of memory areas currently allocated
557 *
558 * Returns an int representing the number of blocks
559 */
560
561int
562xmlMemBlocks(void) {
563 return(debugMemBlocks);
564}
565
Owen Taylor3473f882001-02-23 17:55:21 +0000566#ifdef MEM_LIST
567/**
568 * xmlMemContentShow:
569 * @fp: a FILE descriptor used as the output file
570 * @p: a memory block header
571 *
572 * tries to show some content from the memory block
573 */
574
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000575static void
Owen Taylor3473f882001-02-23 17:55:21 +0000576xmlMemContentShow(FILE *fp, MEMHDR *p)
577{
578 int i,j,len = p->mh_size;
579 const char *buf = (const char *) HDR_2_CLIENT(p);
580
581 if (p == NULL) {
582 fprintf(fp, " NULL");
583 return;
584 }
585
586 for (i = 0;i < len;i++) {
587 if (buf[i] == 0) break;
Daniel Veillard9f28f302002-02-15 20:48:08 +0000588 if (!isprint((unsigned char) buf[i])) break;
Owen Taylor3473f882001-02-23 17:55:21 +0000589 }
590 if ((i < 4) && ((buf[i] != 0) || (i == 0))) {
591 if (len >= 4) {
592 MEMHDR *q;
593 void *cur;
594
595 for (j = 0;j < len -3;j += 4) {
596 cur = *((void **) &buf[j]);
597 q = CLIENT_2_HDR(cur);
598 p = memlist;
599 while (p != NULL) {
600 if (p == q) break;
601 p = p->mh_next;
602 }
603 if ((p != NULL) && (p == q)) {
604 fprintf(fp, " pointer to #%lu at index %d",
605 p->mh_number, j);
606 return;
607 }
608 }
609 }
610 } else if ((i == 0) && (buf[i] == 0)) {
611 fprintf(fp," null");
612 } else {
613 if (buf[i] == 0) fprintf(fp," \"%.25s\"", buf);
614 else {
615 fprintf(fp," [");
616 for (j = 0;j < i;j++)
617 fprintf(fp,"%c", buf[j]);
618 fprintf(fp,"]");
619 }
620 }
621}
622#endif
623
624/**
Owen Taylor3473f882001-02-23 17:55:21 +0000625 * xmlMemDisplay:
626 * @fp: a FILE descriptor used as the output file, if NULL, the result is
627 * written to the file .memorylist
628 *
629 * show in-extenso the memory blocks allocated
630 */
631
632void
633xmlMemDisplay(FILE *fp)
634{
635#ifdef MEM_LIST
636 MEMHDR *p;
Daniel Veillard144024e2002-02-13 21:14:46 +0000637 unsigned idx;
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000638 int nb = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000639#if defined(HAVE_LOCALTIME) && defined(HAVE_STRFTIME)
640 time_t currentTime;
641 char buf[500];
642 struct tm * tstruct;
643
644 currentTime = time(NULL);
645 tstruct = localtime(&currentTime);
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000646 strftime(buf, sizeof(buf) - 1, "%I:%M:%S %p", tstruct);
Owen Taylor3473f882001-02-23 17:55:21 +0000647 fprintf(fp," %s\n\n", buf);
648#endif
649
650
651 fprintf(fp," MEMORY ALLOCATED : %lu, MAX was %lu\n",
652 debugMemSize, debugMaxMemSize);
653 fprintf(fp,"BLOCK NUMBER SIZE TYPE\n");
654 idx = 0;
William M. Brack0622fe82003-11-29 10:47:56 +0000655 xmlMutexLock(xmlMemMutex);
Owen Taylor3473f882001-02-23 17:55:21 +0000656 p = memlist;
657 while (p) {
Daniel Veillard144024e2002-02-13 21:14:46 +0000658 fprintf(fp,"%-5u %6lu %6lu ",idx++,p->mh_number,
659 (unsigned long)p->mh_size);
Owen Taylor3473f882001-02-23 17:55:21 +0000660 switch (p->mh_type) {
661 case STRDUP_TYPE:fprintf(fp,"strdup() in ");break;
662 case MALLOC_TYPE:fprintf(fp,"malloc() in ");break;
Daniel Veillard529233c2004-07-02 12:23:44 +0000663 case REALLOC_TYPE:fprintf(fp,"realloc() in ");break;
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000664 case MALLOC_ATOMIC_TYPE:fprintf(fp,"atomicmalloc() in ");break;
Daniel Veillard529233c2004-07-02 12:23:44 +0000665 case REALLOC_ATOMIC_TYPE:fprintf(fp,"atomicrealloc() in ");break;
666 default:
William M. Brack13dfa872004-09-18 04:52:08 +0000667 fprintf(fp,"Unknown memory block, may be corrupted");
Daniel Veillard529233c2004-07-02 12:23:44 +0000668 xmlMutexUnlock(xmlMemMutex);
669 return;
Owen Taylor3473f882001-02-23 17:55:21 +0000670 }
William M. Brack13dfa872004-09-18 04:52:08 +0000671 if (p->mh_file != NULL) fprintf(fp,"%s(%u)", p->mh_file, p->mh_line);
Owen Taylor3473f882001-02-23 17:55:21 +0000672 if (p->mh_tag != MEMTAG)
673 fprintf(fp," INVALID");
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000674 nb++;
675 if (nb < 100)
676 xmlMemContentShow(fp, p);
677 else
678 fprintf(fp," skip");
679
Owen Taylor3473f882001-02-23 17:55:21 +0000680 fprintf(fp,"\n");
681 p = p->mh_next;
682 }
William M. Brack0622fe82003-11-29 10:47:56 +0000683 xmlMutexUnlock(xmlMemMutex);
Owen Taylor3473f882001-02-23 17:55:21 +0000684#else
685 fprintf(fp,"Memory list not compiled (MEM_LIST not defined !)\n");
686#endif
687}
688
689#ifdef MEM_LIST
690
Daniel Veillard01c13b52002-12-10 15:19:08 +0000691static void debugmem_list_add(MEMHDR *p)
Owen Taylor3473f882001-02-23 17:55:21 +0000692{
693 p->mh_next = memlist;
694 p->mh_prev = NULL;
695 if (memlist) memlist->mh_prev = p;
696 memlist = p;
697#ifdef MEM_LIST_DEBUG
698 if (stderr)
699 Mem_Display(stderr);
700#endif
701}
702
Daniel Veillard01c13b52002-12-10 15:19:08 +0000703static void debugmem_list_delete(MEMHDR *p)
Owen Taylor3473f882001-02-23 17:55:21 +0000704{
705 if (p->mh_next)
706 p->mh_next->mh_prev = p->mh_prev;
707 if (p->mh_prev)
708 p->mh_prev->mh_next = p->mh_next;
709 else memlist = p->mh_next;
710#ifdef MEM_LIST_DEBUG
711 if (stderr)
712 Mem_Display(stderr);
713#endif
714}
715
716#endif
717
718/*
Daniel Veillard01c13b52002-12-10 15:19:08 +0000719 * debugmem_tag_error:
720 *
721 * internal error function.
Owen Taylor3473f882001-02-23 17:55:21 +0000722 */
723
Daniel Veillard01c13b52002-12-10 15:19:08 +0000724static void debugmem_tag_error(void *p)
Owen Taylor3473f882001-02-23 17:55:21 +0000725{
726 xmlGenericError(xmlGenericErrorContext,
727 "Memory tag error occurs :%p \n\t bye\n", p);
728#ifdef MEM_LIST
729 if (stderr)
730 xmlMemDisplay(stderr);
731#endif
732}
733
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000734#ifdef MEM_LIST
Daniel Veillardb44025c2001-10-11 22:55:55 +0000735static FILE *xmlMemoryDumpFile = NULL;
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000736#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000737
Owen Taylor3473f882001-02-23 17:55:21 +0000738/**
Daniel Veillardfb43bd62003-09-29 09:22:39 +0000739 * xmlMemShow:
740 * @fp: a FILE descriptor used as the output file
741 * @nr: number of entries to dump
742 *
743 * show a show display of the memory allocated, and dump
744 * the @nr last allocated areas which were not freed
745 */
746
747void
Daniel Veillardc064b472003-09-29 10:55:05 +0000748xmlMemShow(FILE *fp, int nr ATTRIBUTE_UNUSED)
Daniel Veillardfb43bd62003-09-29 09:22:39 +0000749{
Daniel Veillardfb43bd62003-09-29 09:22:39 +0000750#ifdef MEM_LIST
751 MEMHDR *p;
752#endif
Daniel Veillardfb43bd62003-09-29 09:22:39 +0000753
754 if (fp != NULL)
755 fprintf(fp," MEMORY ALLOCATED : %lu, MAX was %lu\n",
756 debugMemSize, debugMaxMemSize);
Daniel Veillardfb43bd62003-09-29 09:22:39 +0000757#ifdef MEM_LIST
William M. Brack0622fe82003-11-29 10:47:56 +0000758 xmlMutexLock(xmlMemMutex);
Daniel Veillardfb43bd62003-09-29 09:22:39 +0000759 if (nr > 0) {
760 fprintf(fp,"NUMBER SIZE TYPE WHERE\n");
761 p = memlist;
762 while ((p) && nr > 0) {
763 fprintf(fp,"%6lu %6lu ",p->mh_number,(unsigned long)p->mh_size);
764 switch (p->mh_type) {
765 case STRDUP_TYPE:fprintf(fp,"strdup() in ");break;
766 case MALLOC_TYPE:fprintf(fp,"malloc() in ");break;
767 case MALLOC_ATOMIC_TYPE:fprintf(fp,"atomicmalloc() in ");break;
768 case REALLOC_TYPE:fprintf(fp,"realloc() in ");break;
769 case REALLOC_ATOMIC_TYPE:fprintf(fp,"atomicrealloc() in ");break;
770 default:fprintf(fp," ??? in ");break;
771 }
772 if (p->mh_file != NULL)
William M. Brack13dfa872004-09-18 04:52:08 +0000773 fprintf(fp,"%s(%u)", p->mh_file, p->mh_line);
Daniel Veillardfb43bd62003-09-29 09:22:39 +0000774 if (p->mh_tag != MEMTAG)
775 fprintf(fp," INVALID");
776 xmlMemContentShow(fp, p);
777 fprintf(fp,"\n");
778 nr--;
779 p = p->mh_next;
780 }
781 }
William M. Brack0622fe82003-11-29 10:47:56 +0000782 xmlMutexUnlock(xmlMemMutex);
Daniel Veillardfb43bd62003-09-29 09:22:39 +0000783#endif /* MEM_LIST */
Daniel Veillardfb43bd62003-09-29 09:22:39 +0000784}
785
786/**
Owen Taylor3473f882001-02-23 17:55:21 +0000787 * xmlMemoryDump:
788 *
789 * Dump in-extenso the memory blocks allocated to the file .memorylist
790 */
791
792void
793xmlMemoryDump(void)
794{
Daniel Veillardc064b472003-09-29 10:55:05 +0000795#ifdef MEM_LIST
Owen Taylor3473f882001-02-23 17:55:21 +0000796 FILE *dump;
797
Daniel Veillard5997aca2002-03-18 18:36:20 +0000798 if (debugMaxMemSize == 0)
799 return;
Owen Taylor3473f882001-02-23 17:55:21 +0000800 dump = fopen(".memdump", "w");
Daniel Veillardcd337f02001-11-22 18:20:37 +0000801 if (dump == NULL)
802 xmlMemoryDumpFile = stderr;
Owen Taylor3473f882001-02-23 17:55:21 +0000803 else xmlMemoryDumpFile = dump;
804
805 xmlMemDisplay(xmlMemoryDumpFile);
806
807 if (dump != NULL) fclose(dump);
Daniel Veillardc064b472003-09-29 10:55:05 +0000808#endif /* MEM_LIST */
Owen Taylor3473f882001-02-23 17:55:21 +0000809}
810
811
812/****************************************************************
813 * *
814 * Initialization Routines *
815 * *
816 ****************************************************************/
817
Owen Taylor3473f882001-02-23 17:55:21 +0000818/**
819 * xmlInitMemory:
820 *
821 * Initialize the memory layer.
822 *
823 * Returns 0 on success
824 */
Owen Taylor3473f882001-02-23 17:55:21 +0000825int
826xmlInitMemory(void)
827{
Daniel Veillarde15df582004-07-13 15:25:08 +0000828#ifdef HAVE_STDLIB_H
829 char *breakpoint;
830#endif
Daniel Veillardf93a8662004-07-01 12:56:30 +0000831#ifdef DEBUG_MEMORY
832 xmlGenericError(xmlGenericErrorContext,
833 "xmlInitMemory()\n");
834#endif
William M. Brack92029422004-01-04 01:01:14 +0000835 /*
836 This is really not good code (see Bug 130419). Suggestions for
837 improvement will be welcome!
838 */
839 if (xmlMemInitialized) return(-1);
William M. Brack0622fe82003-11-29 10:47:56 +0000840 xmlMemInitialized = 1;
William M. Brack0622fe82003-11-29 10:47:56 +0000841 xmlMemMutex = xmlNewMutex();
Owen Taylor3473f882001-02-23 17:55:21 +0000842
843#ifdef HAVE_STDLIB_H
844 breakpoint = getenv("XML_MEM_BREAKPOINT");
845 if (breakpoint != NULL) {
William M. Brack0622fe82003-11-29 10:47:56 +0000846 sscanf(breakpoint, "%ud", &xmlMemStopAtBlock);
Owen Taylor3473f882001-02-23 17:55:21 +0000847 }
848#endif
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000849#ifdef HAVE_STDLIB_H
850 breakpoint = getenv("XML_MEM_TRACE");
851 if (breakpoint != NULL) {
852 sscanf(breakpoint, "%p", &xmlMemTraceBlockAt);
853 }
854#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000855
856#ifdef DEBUG_MEMORY
857 xmlGenericError(xmlGenericErrorContext,
858 "xmlInitMemory() Ok\n");
859#endif
Daniel Veillard4432df22003-09-28 18:58:27 +0000860 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +0000861}
862
863/**
William M. Brack72ee48d2003-12-30 08:30:19 +0000864 * xmlCleanupMemory:
865 *
Daniel Veillard91b955c2004-12-10 10:26:42 +0000866 * Free up all the memory allocated by the library for its own
867 * use. This should not be called by user level code.
William M. Brack72ee48d2003-12-30 08:30:19 +0000868 */
869void
870xmlCleanupMemory(void) {
Daniel Veillardf93a8662004-07-01 12:56:30 +0000871#ifdef DEBUG_MEMORY
872 xmlGenericError(xmlGenericErrorContext,
873 "xmlCleanupMemory()\n");
874#endif
William M. Brack72ee48d2003-12-30 08:30:19 +0000875 if (xmlMemInitialized == 0)
876 return;
877
878 xmlFreeMutex(xmlMemMutex);
Daniel Veillard1a9b7082004-01-02 10:42:01 +0000879 xmlMemMutex = NULL;
William M. Brack72ee48d2003-12-30 08:30:19 +0000880 xmlMemInitialized = 0;
Daniel Veillardf93a8662004-07-01 12:56:30 +0000881#ifdef DEBUG_MEMORY
882 xmlGenericError(xmlGenericErrorContext,
883 "xmlCleanupMemory() Ok\n");
884#endif
William M. Brack72ee48d2003-12-30 08:30:19 +0000885}
886
887/**
Owen Taylor3473f882001-02-23 17:55:21 +0000888 * xmlMemSetup:
889 * @freeFunc: the free() function to use
890 * @mallocFunc: the malloc() function to use
891 * @reallocFunc: the realloc() function to use
892 * @strdupFunc: the strdup() function to use
893 *
894 * Override the default memory access functions with a new set
895 * This has to be called before any other libxml routines !
896 *
897 * Should this be blocked if there was already some allocations
898 * done ?
899 *
900 * Returns 0 on success
901 */
902int
903xmlMemSetup(xmlFreeFunc freeFunc, xmlMallocFunc mallocFunc,
904 xmlReallocFunc reallocFunc, xmlStrdupFunc strdupFunc) {
Daniel Veillardf93a8662004-07-01 12:56:30 +0000905#ifdef DEBUG_MEMORY
906 xmlGenericError(xmlGenericErrorContext,
907 "xmlMemSetup()\n");
908#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000909 if (freeFunc == NULL)
910 return(-1);
911 if (mallocFunc == NULL)
912 return(-1);
913 if (reallocFunc == NULL)
914 return(-1);
915 if (strdupFunc == NULL)
916 return(-1);
917 xmlFree = freeFunc;
918 xmlMalloc = mallocFunc;
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000919 xmlMallocAtomic = mallocFunc;
Owen Taylor3473f882001-02-23 17:55:21 +0000920 xmlRealloc = reallocFunc;
921 xmlMemStrdup = strdupFunc;
Daniel Veillardf93a8662004-07-01 12:56:30 +0000922#ifdef DEBUG_MEMORY
923 xmlGenericError(xmlGenericErrorContext,
924 "xmlMemSetup() Ok\n");
925#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000926 return(0);
927}
928
929/**
930 * xmlMemGet:
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000931 * @freeFunc: place to save the free() function in use
932 * @mallocFunc: place to save the malloc() function in use
933 * @reallocFunc: place to save the realloc() function in use
934 * @strdupFunc: place to save the strdup() function in use
Owen Taylor3473f882001-02-23 17:55:21 +0000935 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000936 * Provides the memory access functions set currently in use
Owen Taylor3473f882001-02-23 17:55:21 +0000937 *
938 * Returns 0 on success
939 */
940int
941xmlMemGet(xmlFreeFunc *freeFunc, xmlMallocFunc *mallocFunc,
942 xmlReallocFunc *reallocFunc, xmlStrdupFunc *strdupFunc) {
943 if (freeFunc != NULL) *freeFunc = xmlFree;
944 if (mallocFunc != NULL) *mallocFunc = xmlMalloc;
945 if (reallocFunc != NULL) *reallocFunc = xmlRealloc;
946 if (strdupFunc != NULL) *strdupFunc = xmlMemStrdup;
947 return(0);
948}
949
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000950/**
951 * xmlGcMemSetup:
952 * @freeFunc: the free() function to use
953 * @mallocFunc: the malloc() function to use
954 * @mallocAtomicFunc: the malloc() function to use for atomic allocations
955 * @reallocFunc: the realloc() function to use
956 * @strdupFunc: the strdup() function to use
957 *
958 * Override the default memory access functions with a new set
959 * This has to be called before any other libxml routines !
960 * The mallocAtomicFunc is specialized for atomic block
961 * allocations (i.e. of areas useful for garbage collected memory allocators
962 *
963 * Should this be blocked if there was already some allocations
964 * done ?
965 *
966 * Returns 0 on success
967 */
968int
969xmlGcMemSetup(xmlFreeFunc freeFunc, xmlMallocFunc mallocFunc,
970 xmlMallocFunc mallocAtomicFunc, xmlReallocFunc reallocFunc,
971 xmlStrdupFunc strdupFunc) {
Daniel Veillardf93a8662004-07-01 12:56:30 +0000972#ifdef DEBUG_MEMORY
973 xmlGenericError(xmlGenericErrorContext,
974 "xmlGcMemSetup()\n");
975#endif
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000976 if (freeFunc == NULL)
977 return(-1);
978 if (mallocFunc == NULL)
979 return(-1);
980 if (mallocAtomicFunc == NULL)
981 return(-1);
982 if (reallocFunc == NULL)
983 return(-1);
984 if (strdupFunc == NULL)
985 return(-1);
986 xmlFree = freeFunc;
987 xmlMalloc = mallocFunc;
988 xmlMallocAtomic = mallocAtomicFunc;
989 xmlRealloc = reallocFunc;
990 xmlMemStrdup = strdupFunc;
Daniel Veillardf93a8662004-07-01 12:56:30 +0000991#ifdef DEBUG_MEMORY
992 xmlGenericError(xmlGenericErrorContext,
993 "xmlGcMemSetup() Ok\n");
994#endif
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000995 return(0);
996}
997
998/**
999 * xmlGcMemGet:
1000 * @freeFunc: place to save the free() function in use
1001 * @mallocFunc: place to save the malloc() function in use
1002 * @mallocAtomicFunc: place to save the atomic malloc() function in use
1003 * @reallocFunc: place to save the realloc() function in use
1004 * @strdupFunc: place to save the strdup() function in use
1005 *
1006 * Provides the memory access functions set currently in use
1007 * The mallocAtomicFunc is specialized for atomic block
1008 * allocations (i.e. of areas useful for garbage collected memory allocators
1009 *
1010 * Returns 0 on success
1011 */
1012int
1013xmlGcMemGet(xmlFreeFunc *freeFunc, xmlMallocFunc *mallocFunc,
1014 xmlMallocFunc *mallocAtomicFunc, xmlReallocFunc *reallocFunc,
1015 xmlStrdupFunc *strdupFunc) {
1016 if (freeFunc != NULL) *freeFunc = xmlFree;
1017 if (mallocFunc != NULL) *mallocFunc = xmlMalloc;
1018 if (mallocAtomicFunc != NULL) *mallocAtomicFunc = xmlMallocAtomic;
1019 if (reallocFunc != NULL) *reallocFunc = xmlRealloc;
1020 if (strdupFunc != NULL) *strdupFunc = xmlMemStrdup;
1021 return(0);
1022}
1023