blob: 88d191b95843805af3beb6c198f7e6116c063aed [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;
53static unsigned long debugMaxMemSize = 0;
William M. Brack0622fe82003-11-29 10:47:56 +000054static xmlMutexPtr xmlMemMutex = NULL;
Daniel Veillard4432df22003-09-28 18:58:27 +000055
Daniel Veillard56a4cb82001-03-24 17:00:36 +000056void xmlMallocBreakpoint(void);
Daniel Veillard56a4cb82001-03-24 17:00:36 +000057
58/************************************************************************
59 * *
60 * Macros, variables and associated types *
61 * *
62 ************************************************************************/
63
William M. Brack5ab479b2004-06-10 13:00:15 +000064#if !defined(LIBXML_THREAD_ENABLED) && !defined(LIBXML_THREAD_ALLOC_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +000065#ifdef xmlMalloc
66#undef xmlMalloc
67#endif
68#ifdef xmlRealloc
69#undef xmlRealloc
70#endif
71#ifdef xmlMemStrdup
72#undef xmlMemStrdup
73#endif
William M. Brack5ab479b2004-06-10 13:00:15 +000074#endif
Owen Taylor3473f882001-02-23 17:55:21 +000075
76/*
77 * Each of the blocks allocated begin with a header containing informations
78 */
79
80#define MEMTAG 0x5aa5
81
82#define MALLOC_TYPE 1
83#define REALLOC_TYPE 2
84#define STRDUP_TYPE 3
Daniel Veillard3c908dc2003-04-19 00:07:51 +000085#define MALLOC_ATOMIC_TYPE 4
86#define REALLOC_ATOMIC_TYPE 5
Owen Taylor3473f882001-02-23 17:55:21 +000087
88typedef struct memnod {
89 unsigned int mh_tag;
90 unsigned int mh_type;
91 unsigned long mh_number;
92 size_t mh_size;
93#ifdef MEM_LIST
94 struct memnod *mh_next;
95 struct memnod *mh_prev;
96#endif
97 const char *mh_file;
98 unsigned int mh_line;
99} MEMHDR;
100
101
102#ifdef SUN4
103#define ALIGN_SIZE 16
104#else
105#define ALIGN_SIZE sizeof(double)
106#endif
107#define HDR_SIZE sizeof(MEMHDR)
108#define RESERVE_SIZE (((HDR_SIZE + (ALIGN_SIZE-1)) \
109 / ALIGN_SIZE ) * ALIGN_SIZE)
110
111
112#define CLIENT_2_HDR(a) ((MEMHDR *) (((char *) (a)) - RESERVE_SIZE))
113#define HDR_2_CLIENT(a) ((void *) (((char *) (a)) + RESERVE_SIZE))
114
115
William M. Brack0622fe82003-11-29 10:47:56 +0000116static unsigned int block=0;
117static unsigned int xmlMemStopAtBlock = 0;
Daniel Veillardb44025c2001-10-11 22:55:55 +0000118static void *xmlMemTraceBlockAt = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +0000119#ifdef MEM_LIST
120static MEMHDR *memlist = NULL;
121#endif
122
Daniel Veillard01c13b52002-12-10 15:19:08 +0000123static void debugmem_tag_error(void *addr);
Owen Taylor3473f882001-02-23 17:55:21 +0000124#ifdef MEM_LIST
Daniel Veillard01c13b52002-12-10 15:19:08 +0000125static void debugmem_list_add(MEMHDR *);
126static void debugmem_list_delete(MEMHDR *);
Owen Taylor3473f882001-02-23 17:55:21 +0000127#endif
128#define Mem_Tag_Err(a) debugmem_tag_error(a);
129
130#ifndef TEST_POINT
131#define TEST_POINT
132#endif
133
134/**
135 * xmlMallocBreakpoint:
136 *
137 * Breakpoint to use in conjunction with xmlMemStopAtBlock. When the block
138 * number reaches the specified value this function is called. One need to add a breakpoint
139 * to it to get the context in which the given block is allocated.
140 */
141
142void
143xmlMallocBreakpoint(void) {
144 xmlGenericError(xmlGenericErrorContext,
145 "xmlMallocBreakpoint reached on block %d\n", xmlMemStopAtBlock);
146}
147
148/**
149 * xmlMallocLoc:
150 * @size: an int specifying the size in byte to allocate.
151 * @file: the file name or NULL
152 * @line: the line number
153 *
154 * a malloc() equivalent, with logging of the allocation info.
155 *
156 * Returns a pointer to the allocated area or NULL in case of lack of memory.
157 */
158
159void *
Daniel Veillard8599e702001-07-17 21:38:51 +0000160xmlMallocLoc(size_t size, const char * file, int line)
Owen Taylor3473f882001-02-23 17:55:21 +0000161{
162 MEMHDR *p;
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000163 void *ret;
Owen Taylor3473f882001-02-23 17:55:21 +0000164
165 if (!xmlMemInitialized) xmlInitMemory();
166#ifdef DEBUG_MEMORY
167 xmlGenericError(xmlGenericErrorContext,
168 "Malloc(%d)\n",size);
169#endif
170
171 TEST_POINT
172
173 p = (MEMHDR *) malloc(RESERVE_SIZE+size);
174
175 if (!p) {
176 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard26908ab2002-01-01 16:50:03 +0000177 "xmlMallocLoc : Out of free space\n");
Owen Taylor3473f882001-02-23 17:55:21 +0000178 xmlMemoryDump();
179 return(NULL);
180 }
181 p->mh_tag = MEMTAG;
Owen Taylor3473f882001-02-23 17:55:21 +0000182 p->mh_size = size;
183 p->mh_type = MALLOC_TYPE;
184 p->mh_file = file;
185 p->mh_line = line;
William M. Brack0622fe82003-11-29 10:47:56 +0000186 xmlMutexLock(xmlMemMutex);
187 p->mh_number = ++block;
Owen Taylor3473f882001-02-23 17:55:21 +0000188 debugMemSize += size;
189 if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
190#ifdef MEM_LIST
191 debugmem_list_add(p);
192#endif
William M. Brack0622fe82003-11-29 10:47:56 +0000193 xmlMutexUnlock(xmlMemMutex);
194
Owen Taylor3473f882001-02-23 17:55:21 +0000195#ifdef DEBUG_MEMORY
196 xmlGenericError(xmlGenericErrorContext,
197 "Malloc(%d) Ok\n",size);
198#endif
199
William M. Brack0622fe82003-11-29 10:47:56 +0000200 if (xmlMemStopAtBlock == p->mh_number) xmlMallocBreakpoint();
Owen Taylor3473f882001-02-23 17:55:21 +0000201
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000202 ret = HDR_2_CLIENT(p);
203
204 if (xmlMemTraceBlockAt == ret) {
205 xmlGenericError(xmlGenericErrorContext,
206 "%p : Malloc(%d) Ok\n", xmlMemTraceBlockAt, size);
207 xmlMallocBreakpoint();
208 }
209
Owen Taylor3473f882001-02-23 17:55:21 +0000210 TEST_POINT
211
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000212 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000213}
214
215/**
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000216 * xmlMallocAtomicLoc:
217 * @size: an int specifying the size in byte to allocate.
218 * @file: the file name or NULL
219 * @line: the line number
220 *
221 * a malloc() equivalent, with logging of the allocation info.
222 *
223 * Returns a pointer to the allocated area or NULL in case of lack of memory.
224 */
225
226void *
227xmlMallocAtomicLoc(size_t size, const char * file, int line)
228{
229 MEMHDR *p;
230 void *ret;
231
232 if (!xmlMemInitialized) xmlInitMemory();
233#ifdef DEBUG_MEMORY
234 xmlGenericError(xmlGenericErrorContext,
235 "Malloc(%d)\n",size);
236#endif
237
238 TEST_POINT
239
240 p = (MEMHDR *) malloc(RESERVE_SIZE+size);
241
242 if (!p) {
243 xmlGenericError(xmlGenericErrorContext,
244 "xmlMallocLoc : Out of free space\n");
245 xmlMemoryDump();
246 return(NULL);
247 }
248 p->mh_tag = MEMTAG;
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000249 p->mh_size = size;
250 p->mh_type = MALLOC_ATOMIC_TYPE;
251 p->mh_file = file;
252 p->mh_line = line;
William M. Brack0622fe82003-11-29 10:47:56 +0000253 xmlMutexLock(xmlMemMutex);
254 p->mh_number = ++block;
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000255 debugMemSize += size;
256 if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
257#ifdef MEM_LIST
258 debugmem_list_add(p);
259#endif
William M. Brack0622fe82003-11-29 10:47:56 +0000260 xmlMutexUnlock(xmlMemMutex);
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000261
262#ifdef DEBUG_MEMORY
263 xmlGenericError(xmlGenericErrorContext,
264 "Malloc(%d) Ok\n",size);
265#endif
266
William M. Brack0622fe82003-11-29 10:47:56 +0000267 if (xmlMemStopAtBlock == p->mh_number) xmlMallocBreakpoint();
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000268
269 ret = HDR_2_CLIENT(p);
270
271 if (xmlMemTraceBlockAt == ret) {
272 xmlGenericError(xmlGenericErrorContext,
273 "%p : Malloc(%d) Ok\n", xmlMemTraceBlockAt, size);
274 xmlMallocBreakpoint();
275 }
276
277 TEST_POINT
278
279 return(ret);
280}
281/**
Owen Taylor3473f882001-02-23 17:55:21 +0000282 * xmlMemMalloc:
283 * @size: an int specifying the size in byte to allocate.
284 *
285 * a malloc() equivalent, with logging of the allocation info.
286 *
287 * Returns a pointer to the allocated area or NULL in case of lack of memory.
288 */
289
290void *
Daniel Veillard8599e702001-07-17 21:38:51 +0000291xmlMemMalloc(size_t size)
Owen Taylor3473f882001-02-23 17:55:21 +0000292{
293 return(xmlMallocLoc(size, "none", 0));
294}
295
296/**
297 * xmlReallocLoc:
298 * @ptr: the initial memory block pointer
299 * @size: an int specifying the size in byte to allocate.
300 * @file: the file name or NULL
301 * @line: the line number
302 *
303 * a realloc() equivalent, with logging of the allocation info.
304 *
305 * Returns a pointer to the allocated area or NULL in case of lack of memory.
306 */
307
308void *
Daniel Veillard8599e702001-07-17 21:38:51 +0000309xmlReallocLoc(void *ptr,size_t size, const char * file, int line)
Owen Taylor3473f882001-02-23 17:55:21 +0000310{
311 MEMHDR *p;
312 unsigned long number;
Daniel Veillard529233c2004-07-02 12:23:44 +0000313#ifdef DEBUG_MEMORY
314 size_t oldsize;
315#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000316
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000317 if (ptr == NULL)
Aleksey Sanine9f08112004-01-22 22:20:31 +0000318 return(xmlMallocLoc(size, file, line));
319
320 if (!xmlMemInitialized) xmlInitMemory();
Owen Taylor3473f882001-02-23 17:55:21 +0000321 TEST_POINT
322
323 p = CLIENT_2_HDR(ptr);
324 number = p->mh_number;
325 if (p->mh_tag != MEMTAG) {
326 Mem_Tag_Err(p);
327 goto error;
328 }
329 p->mh_tag = ~MEMTAG;
William M. Brack0622fe82003-11-29 10:47:56 +0000330 xmlMutexLock(xmlMemMutex);
Owen Taylor3473f882001-02-23 17:55:21 +0000331 debugMemSize -= p->mh_size;
Daniel Veillard529233c2004-07-02 12:23:44 +0000332#ifdef DEBUG_MEMORY
333 oldsize = p->mh_size;
334#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000335#ifdef MEM_LIST
336 debugmem_list_delete(p);
337#endif
William M. Brack0622fe82003-11-29 10:47:56 +0000338 xmlMutexUnlock(xmlMemMutex);
339
Owen Taylor3473f882001-02-23 17:55:21 +0000340 p = (MEMHDR *) realloc(p,RESERVE_SIZE+size);
341 if (!p) {
342 goto error;
343 }
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000344 if (xmlMemTraceBlockAt == ptr) {
345 xmlGenericError(xmlGenericErrorContext,
346 "%p : Realloced(%d -> %d) Ok\n",
347 xmlMemTraceBlockAt, p->mh_size, size);
348 xmlMallocBreakpoint();
349 }
Owen Taylor3473f882001-02-23 17:55:21 +0000350 p->mh_tag = MEMTAG;
351 p->mh_number = number;
352 p->mh_type = REALLOC_TYPE;
353 p->mh_size = size;
354 p->mh_file = file;
355 p->mh_line = line;
William M. Brack0622fe82003-11-29 10:47:56 +0000356 xmlMutexLock(xmlMemMutex);
Owen Taylor3473f882001-02-23 17:55:21 +0000357 debugMemSize += size;
358 if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
359#ifdef MEM_LIST
360 debugmem_list_add(p);
361#endif
William M. Brack0622fe82003-11-29 10:47:56 +0000362 xmlMutexUnlock(xmlMemMutex);
Owen Taylor3473f882001-02-23 17:55:21 +0000363
364 TEST_POINT
365
Daniel Veillard529233c2004-07-02 12:23:44 +0000366#ifdef DEBUG_MEMORY
367 xmlGenericError(xmlGenericErrorContext,
368 "Realloced(%d to %d) Ok\n", oldsize, size);
369#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000370 return(HDR_2_CLIENT(p));
371
372error:
373 return(NULL);
374}
375
376/**
377 * xmlMemRealloc:
378 * @ptr: the initial memory block pointer
379 * @size: an int specifying the size in byte to allocate.
380 *
381 * a realloc() equivalent, with logging of the allocation info.
382 *
383 * Returns a pointer to the allocated area or NULL in case of lack of memory.
384 */
385
386void *
Daniel Veillard8599e702001-07-17 21:38:51 +0000387xmlMemRealloc(void *ptr,size_t size) {
Owen Taylor3473f882001-02-23 17:55:21 +0000388 return(xmlReallocLoc(ptr, size, "none", 0));
389}
390
391/**
392 * xmlMemFree:
393 * @ptr: the memory block pointer
394 *
395 * a free() equivalent, with error checking.
396 */
397void
398xmlMemFree(void *ptr)
399{
400 MEMHDR *p;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000401 char *target;
Daniel Veillard529233c2004-07-02 12:23:44 +0000402#ifdef DEBUG_MEMORY
403 size_t size;
404#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000405
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000406 if (ptr == (void *) -1) {
407 xmlGenericError(xmlGenericErrorContext,
408 "trying to free pointer from freed area\n");
409 goto error;
410 }
411
412 if (xmlMemTraceBlockAt == ptr) {
413 xmlGenericError(xmlGenericErrorContext,
414 "%p : Freed()\n", xmlMemTraceBlockAt);
415 xmlMallocBreakpoint();
416 }
417
Owen Taylor3473f882001-02-23 17:55:21 +0000418 TEST_POINT
419
Daniel Veillard92ad2102001-03-27 12:47:33 +0000420 target = (char *) ptr;
421
Owen Taylor3473f882001-02-23 17:55:21 +0000422 p = CLIENT_2_HDR(ptr);
423 if (p->mh_tag != MEMTAG) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000424 Mem_Tag_Err(p);
425 goto error;
Owen Taylor3473f882001-02-23 17:55:21 +0000426 }
427 p->mh_tag = ~MEMTAG;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000428 memset(target, -1, p->mh_size);
William M. Brack0622fe82003-11-29 10:47:56 +0000429 xmlMutexLock(xmlMemMutex);
430 debugMemSize -= p->mh_size;
Daniel Veillard529233c2004-07-02 12:23:44 +0000431#ifdef DEBUG_MEMORY
432 size = p->mh_size;
433#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000434#ifdef MEM_LIST
435 debugmem_list_delete(p);
436#endif
William M. Brack0622fe82003-11-29 10:47:56 +0000437 xmlMutexUnlock(xmlMemMutex);
438
Owen Taylor3473f882001-02-23 17:55:21 +0000439 free(p);
440
441 TEST_POINT
442
Daniel Veillard529233c2004-07-02 12:23:44 +0000443#ifdef DEBUG_MEMORY
444 xmlGenericError(xmlGenericErrorContext,
445 "Freed(%d) Ok\n", size);
446#endif
447
Owen Taylor3473f882001-02-23 17:55:21 +0000448 return;
449
450error:
451 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard26908ab2002-01-01 16:50:03 +0000452 "xmlMemFree(%lX) error\n", (unsigned long) ptr);
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000453 xmlMallocBreakpoint();
Owen Taylor3473f882001-02-23 17:55:21 +0000454 return;
455}
456
457/**
458 * xmlMemStrdupLoc:
Daniel Veillard9d06d302002-01-22 18:15:52 +0000459 * @str: the initial string pointer
Owen Taylor3473f882001-02-23 17:55:21 +0000460 * @file: the file name or NULL
461 * @line: the line number
462 *
463 * a strdup() equivalent, with logging of the allocation info.
464 *
Daniel Veillard26908ab2002-01-01 16:50:03 +0000465 * Returns a pointer to the new string or NULL if allocation error occurred.
Owen Taylor3473f882001-02-23 17:55:21 +0000466 */
467
468char *
469xmlMemStrdupLoc(const char *str, const char *file, int line)
470{
471 char *s;
472 size_t size = strlen(str) + 1;
473 MEMHDR *p;
474
475 if (!xmlMemInitialized) xmlInitMemory();
476 TEST_POINT
477
478 p = (MEMHDR *) malloc(RESERVE_SIZE+size);
479 if (!p) {
480 goto error;
481 }
482 p->mh_tag = MEMTAG;
Owen Taylor3473f882001-02-23 17:55:21 +0000483 p->mh_size = size;
484 p->mh_type = STRDUP_TYPE;
485 p->mh_file = file;
486 p->mh_line = line;
William M. Brack0622fe82003-11-29 10:47:56 +0000487 xmlMutexLock(xmlMemMutex);
488 p->mh_number = ++block;
Owen Taylor3473f882001-02-23 17:55:21 +0000489 debugMemSize += size;
490 if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
491#ifdef MEM_LIST
492 debugmem_list_add(p);
493#endif
William M. Brack0622fe82003-11-29 10:47:56 +0000494 xmlMutexUnlock(xmlMemMutex);
495
Owen Taylor3473f882001-02-23 17:55:21 +0000496 s = (char *) HDR_2_CLIENT(p);
497
William M. Brack0622fe82003-11-29 10:47:56 +0000498 if (xmlMemStopAtBlock == p->mh_number) xmlMallocBreakpoint();
Owen Taylor3473f882001-02-23 17:55:21 +0000499
500 if (s != NULL)
501 strcpy(s,str);
502 else
503 goto error;
504
505 TEST_POINT
506
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000507 if (xmlMemTraceBlockAt == s) {
508 xmlGenericError(xmlGenericErrorContext,
509 "%p : Strdup() Ok\n", xmlMemTraceBlockAt);
510 xmlMallocBreakpoint();
511 }
512
Owen Taylor3473f882001-02-23 17:55:21 +0000513 return(s);
514
515error:
516 return(NULL);
517}
518
519/**
520 * xmlMemoryStrdup:
Daniel Veillard01c13b52002-12-10 15:19:08 +0000521 * @str: the initial string pointer
Owen Taylor3473f882001-02-23 17:55:21 +0000522 *
523 * a strdup() equivalent, with logging of the allocation info.
524 *
Daniel Veillard26908ab2002-01-01 16:50:03 +0000525 * Returns a pointer to the new string or NULL if allocation error occurred.
Owen Taylor3473f882001-02-23 17:55:21 +0000526 */
527
528char *
529xmlMemoryStrdup(const char *str) {
530 return(xmlMemStrdupLoc(str, "none", 0));
531}
532
533/**
534 * xmlMemUsed:
535 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000536 * Provides the amount of memory currently allocated
Owen Taylor3473f882001-02-23 17:55:21 +0000537 *
538 * Returns an int representing the amount of memory allocated.
539 */
540
541int
542xmlMemUsed(void) {
543 return(debugMemSize);
544}
545
546#ifdef MEM_LIST
547/**
548 * xmlMemContentShow:
549 * @fp: a FILE descriptor used as the output file
550 * @p: a memory block header
551 *
552 * tries to show some content from the memory block
553 */
554
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000555static void
Owen Taylor3473f882001-02-23 17:55:21 +0000556xmlMemContentShow(FILE *fp, MEMHDR *p)
557{
558 int i,j,len = p->mh_size;
559 const char *buf = (const char *) HDR_2_CLIENT(p);
560
561 if (p == NULL) {
562 fprintf(fp, " NULL");
563 return;
564 }
565
566 for (i = 0;i < len;i++) {
567 if (buf[i] == 0) break;
Daniel Veillard9f28f302002-02-15 20:48:08 +0000568 if (!isprint((unsigned char) buf[i])) break;
Owen Taylor3473f882001-02-23 17:55:21 +0000569 }
570 if ((i < 4) && ((buf[i] != 0) || (i == 0))) {
571 if (len >= 4) {
572 MEMHDR *q;
573 void *cur;
574
575 for (j = 0;j < len -3;j += 4) {
576 cur = *((void **) &buf[j]);
577 q = CLIENT_2_HDR(cur);
578 p = memlist;
579 while (p != NULL) {
580 if (p == q) break;
581 p = p->mh_next;
582 }
583 if ((p != NULL) && (p == q)) {
584 fprintf(fp, " pointer to #%lu at index %d",
585 p->mh_number, j);
586 return;
587 }
588 }
589 }
590 } else if ((i == 0) && (buf[i] == 0)) {
591 fprintf(fp," null");
592 } else {
593 if (buf[i] == 0) fprintf(fp," \"%.25s\"", buf);
594 else {
595 fprintf(fp," [");
596 for (j = 0;j < i;j++)
597 fprintf(fp,"%c", buf[j]);
598 fprintf(fp,"]");
599 }
600 }
601}
602#endif
603
604/**
Owen Taylor3473f882001-02-23 17:55:21 +0000605 * xmlMemDisplay:
606 * @fp: a FILE descriptor used as the output file, if NULL, the result is
607 * written to the file .memorylist
608 *
609 * show in-extenso the memory blocks allocated
610 */
611
612void
613xmlMemDisplay(FILE *fp)
614{
615#ifdef MEM_LIST
616 MEMHDR *p;
Daniel Veillard144024e2002-02-13 21:14:46 +0000617 unsigned idx;
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000618 int nb = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000619#if defined(HAVE_LOCALTIME) && defined(HAVE_STRFTIME)
620 time_t currentTime;
621 char buf[500];
622 struct tm * tstruct;
623
624 currentTime = time(NULL);
625 tstruct = localtime(&currentTime);
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000626 strftime(buf, sizeof(buf) - 1, "%I:%M:%S %p", tstruct);
Owen Taylor3473f882001-02-23 17:55:21 +0000627 fprintf(fp," %s\n\n", buf);
628#endif
629
630
631 fprintf(fp," MEMORY ALLOCATED : %lu, MAX was %lu\n",
632 debugMemSize, debugMaxMemSize);
633 fprintf(fp,"BLOCK NUMBER SIZE TYPE\n");
634 idx = 0;
William M. Brack0622fe82003-11-29 10:47:56 +0000635 xmlMutexLock(xmlMemMutex);
Owen Taylor3473f882001-02-23 17:55:21 +0000636 p = memlist;
637 while (p) {
Daniel Veillard144024e2002-02-13 21:14:46 +0000638 fprintf(fp,"%-5u %6lu %6lu ",idx++,p->mh_number,
639 (unsigned long)p->mh_size);
Owen Taylor3473f882001-02-23 17:55:21 +0000640 switch (p->mh_type) {
641 case STRDUP_TYPE:fprintf(fp,"strdup() in ");break;
642 case MALLOC_TYPE:fprintf(fp,"malloc() in ");break;
Daniel Veillard529233c2004-07-02 12:23:44 +0000643 case REALLOC_TYPE:fprintf(fp,"realloc() in ");break;
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000644 case MALLOC_ATOMIC_TYPE:fprintf(fp,"atomicmalloc() in ");break;
Daniel Veillard529233c2004-07-02 12:23:44 +0000645 case REALLOC_ATOMIC_TYPE:fprintf(fp,"atomicrealloc() in ");break;
646 default:
647 fprintf(fp,"Unknow memory block, corruped maybe");
648 xmlMutexUnlock(xmlMemMutex);
649 return;
Owen Taylor3473f882001-02-23 17:55:21 +0000650 }
Daniel Veillard529233c2004-07-02 12:23:44 +0000651 if (p->mh_file != NULL) fprintf(fp,"%s(%d)", p->mh_file, p->mh_line);
Owen Taylor3473f882001-02-23 17:55:21 +0000652 if (p->mh_tag != MEMTAG)
653 fprintf(fp," INVALID");
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000654 nb++;
655 if (nb < 100)
656 xmlMemContentShow(fp, p);
657 else
658 fprintf(fp," skip");
659
Owen Taylor3473f882001-02-23 17:55:21 +0000660 fprintf(fp,"\n");
661 p = p->mh_next;
662 }
William M. Brack0622fe82003-11-29 10:47:56 +0000663 xmlMutexUnlock(xmlMemMutex);
Owen Taylor3473f882001-02-23 17:55:21 +0000664#else
665 fprintf(fp,"Memory list not compiled (MEM_LIST not defined !)\n");
666#endif
667}
668
669#ifdef MEM_LIST
670
Daniel Veillard01c13b52002-12-10 15:19:08 +0000671static void debugmem_list_add(MEMHDR *p)
Owen Taylor3473f882001-02-23 17:55:21 +0000672{
673 p->mh_next = memlist;
674 p->mh_prev = NULL;
675 if (memlist) memlist->mh_prev = p;
676 memlist = p;
677#ifdef MEM_LIST_DEBUG
678 if (stderr)
679 Mem_Display(stderr);
680#endif
681}
682
Daniel Veillard01c13b52002-12-10 15:19:08 +0000683static void debugmem_list_delete(MEMHDR *p)
Owen Taylor3473f882001-02-23 17:55:21 +0000684{
685 if (p->mh_next)
686 p->mh_next->mh_prev = p->mh_prev;
687 if (p->mh_prev)
688 p->mh_prev->mh_next = p->mh_next;
689 else memlist = p->mh_next;
690#ifdef MEM_LIST_DEBUG
691 if (stderr)
692 Mem_Display(stderr);
693#endif
694}
695
696#endif
697
698/*
Daniel Veillard01c13b52002-12-10 15:19:08 +0000699 * debugmem_tag_error:
700 *
701 * internal error function.
Owen Taylor3473f882001-02-23 17:55:21 +0000702 */
703
Daniel Veillard01c13b52002-12-10 15:19:08 +0000704static void debugmem_tag_error(void *p)
Owen Taylor3473f882001-02-23 17:55:21 +0000705{
706 xmlGenericError(xmlGenericErrorContext,
707 "Memory tag error occurs :%p \n\t bye\n", p);
708#ifdef MEM_LIST
709 if (stderr)
710 xmlMemDisplay(stderr);
711#endif
712}
713
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000714#ifdef MEM_LIST
Daniel Veillardb44025c2001-10-11 22:55:55 +0000715static FILE *xmlMemoryDumpFile = NULL;
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000716#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000717
Owen Taylor3473f882001-02-23 17:55:21 +0000718/**
Daniel Veillardfb43bd62003-09-29 09:22:39 +0000719 * xmlMemShow:
720 * @fp: a FILE descriptor used as the output file
721 * @nr: number of entries to dump
722 *
723 * show a show display of the memory allocated, and dump
724 * the @nr last allocated areas which were not freed
725 */
726
727void
Daniel Veillardc064b472003-09-29 10:55:05 +0000728xmlMemShow(FILE *fp, int nr ATTRIBUTE_UNUSED)
Daniel Veillardfb43bd62003-09-29 09:22:39 +0000729{
Daniel Veillardfb43bd62003-09-29 09:22:39 +0000730#ifdef MEM_LIST
731 MEMHDR *p;
732#endif
Daniel Veillardfb43bd62003-09-29 09:22:39 +0000733
734 if (fp != NULL)
735 fprintf(fp," MEMORY ALLOCATED : %lu, MAX was %lu\n",
736 debugMemSize, debugMaxMemSize);
Daniel Veillardfb43bd62003-09-29 09:22:39 +0000737#ifdef MEM_LIST
William M. Brack0622fe82003-11-29 10:47:56 +0000738 xmlMutexLock(xmlMemMutex);
Daniel Veillardfb43bd62003-09-29 09:22:39 +0000739 if (nr > 0) {
740 fprintf(fp,"NUMBER SIZE TYPE WHERE\n");
741 p = memlist;
742 while ((p) && nr > 0) {
743 fprintf(fp,"%6lu %6lu ",p->mh_number,(unsigned long)p->mh_size);
744 switch (p->mh_type) {
745 case STRDUP_TYPE:fprintf(fp,"strdup() in ");break;
746 case MALLOC_TYPE:fprintf(fp,"malloc() in ");break;
747 case MALLOC_ATOMIC_TYPE:fprintf(fp,"atomicmalloc() in ");break;
748 case REALLOC_TYPE:fprintf(fp,"realloc() in ");break;
749 case REALLOC_ATOMIC_TYPE:fprintf(fp,"atomicrealloc() in ");break;
750 default:fprintf(fp," ??? in ");break;
751 }
752 if (p->mh_file != NULL)
753 fprintf(fp,"%s(%d)", p->mh_file, p->mh_line);
754 if (p->mh_tag != MEMTAG)
755 fprintf(fp," INVALID");
756 xmlMemContentShow(fp, p);
757 fprintf(fp,"\n");
758 nr--;
759 p = p->mh_next;
760 }
761 }
William M. Brack0622fe82003-11-29 10:47:56 +0000762 xmlMutexUnlock(xmlMemMutex);
Daniel Veillardfb43bd62003-09-29 09:22:39 +0000763#endif /* MEM_LIST */
Daniel Veillardfb43bd62003-09-29 09:22:39 +0000764}
765
766/**
Owen Taylor3473f882001-02-23 17:55:21 +0000767 * xmlMemoryDump:
768 *
769 * Dump in-extenso the memory blocks allocated to the file .memorylist
770 */
771
772void
773xmlMemoryDump(void)
774{
Daniel Veillardc064b472003-09-29 10:55:05 +0000775#ifdef MEM_LIST
Owen Taylor3473f882001-02-23 17:55:21 +0000776 FILE *dump;
777
Daniel Veillard5997aca2002-03-18 18:36:20 +0000778 if (debugMaxMemSize == 0)
779 return;
Owen Taylor3473f882001-02-23 17:55:21 +0000780 dump = fopen(".memdump", "w");
Daniel Veillardcd337f02001-11-22 18:20:37 +0000781 if (dump == NULL)
782 xmlMemoryDumpFile = stderr;
Owen Taylor3473f882001-02-23 17:55:21 +0000783 else xmlMemoryDumpFile = dump;
784
785 xmlMemDisplay(xmlMemoryDumpFile);
786
787 if (dump != NULL) fclose(dump);
Daniel Veillardc064b472003-09-29 10:55:05 +0000788#endif /* MEM_LIST */
Owen Taylor3473f882001-02-23 17:55:21 +0000789}
790
791
792/****************************************************************
793 * *
794 * Initialization Routines *
795 * *
796 ****************************************************************/
797
Owen Taylor3473f882001-02-23 17:55:21 +0000798/**
799 * xmlInitMemory:
800 *
801 * Initialize the memory layer.
802 *
803 * Returns 0 on success
804 */
Owen Taylor3473f882001-02-23 17:55:21 +0000805int
806xmlInitMemory(void)
807{
Daniel Veillarde15df582004-07-13 15:25:08 +0000808#ifdef HAVE_STDLIB_H
809 char *breakpoint;
810#endif
Daniel Veillardf93a8662004-07-01 12:56:30 +0000811#ifdef DEBUG_MEMORY
812 xmlGenericError(xmlGenericErrorContext,
813 "xmlInitMemory()\n");
814#endif
William M. Brack92029422004-01-04 01:01:14 +0000815 /*
816 This is really not good code (see Bug 130419). Suggestions for
817 improvement will be welcome!
818 */
819 if (xmlMemInitialized) return(-1);
William M. Brack0622fe82003-11-29 10:47:56 +0000820 xmlMemInitialized = 1;
William M. Brack0622fe82003-11-29 10:47:56 +0000821 xmlMemMutex = xmlNewMutex();
Owen Taylor3473f882001-02-23 17:55:21 +0000822
823#ifdef HAVE_STDLIB_H
824 breakpoint = getenv("XML_MEM_BREAKPOINT");
825 if (breakpoint != NULL) {
William M. Brack0622fe82003-11-29 10:47:56 +0000826 sscanf(breakpoint, "%ud", &xmlMemStopAtBlock);
Owen Taylor3473f882001-02-23 17:55:21 +0000827 }
828#endif
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000829#ifdef HAVE_STDLIB_H
830 breakpoint = getenv("XML_MEM_TRACE");
831 if (breakpoint != NULL) {
832 sscanf(breakpoint, "%p", &xmlMemTraceBlockAt);
833 }
834#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000835
836#ifdef DEBUG_MEMORY
837 xmlGenericError(xmlGenericErrorContext,
838 "xmlInitMemory() Ok\n");
839#endif
Daniel Veillard4432df22003-09-28 18:58:27 +0000840 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +0000841}
842
843/**
William M. Brack72ee48d2003-12-30 08:30:19 +0000844 * xmlCleanupMemory:
845 *
846 * Free up all the memory associated with memorys
847 */
848void
849xmlCleanupMemory(void) {
Daniel Veillardf93a8662004-07-01 12:56:30 +0000850#ifdef DEBUG_MEMORY
851 xmlGenericError(xmlGenericErrorContext,
852 "xmlCleanupMemory()\n");
853#endif
William M. Brack72ee48d2003-12-30 08:30:19 +0000854 if (xmlMemInitialized == 0)
855 return;
856
857 xmlFreeMutex(xmlMemMutex);
Daniel Veillard1a9b7082004-01-02 10:42:01 +0000858 xmlMemMutex = NULL;
William M. Brack72ee48d2003-12-30 08:30:19 +0000859 xmlMemInitialized = 0;
Daniel Veillardf93a8662004-07-01 12:56:30 +0000860#ifdef DEBUG_MEMORY
861 xmlGenericError(xmlGenericErrorContext,
862 "xmlCleanupMemory() Ok\n");
863#endif
William M. Brack72ee48d2003-12-30 08:30:19 +0000864}
865
866/**
Owen Taylor3473f882001-02-23 17:55:21 +0000867 * xmlMemSetup:
868 * @freeFunc: the free() function to use
869 * @mallocFunc: the malloc() function to use
870 * @reallocFunc: the realloc() function to use
871 * @strdupFunc: the strdup() function to use
872 *
873 * Override the default memory access functions with a new set
874 * This has to be called before any other libxml routines !
875 *
876 * Should this be blocked if there was already some allocations
877 * done ?
878 *
879 * Returns 0 on success
880 */
881int
882xmlMemSetup(xmlFreeFunc freeFunc, xmlMallocFunc mallocFunc,
883 xmlReallocFunc reallocFunc, xmlStrdupFunc strdupFunc) {
Daniel Veillardf93a8662004-07-01 12:56:30 +0000884#ifdef DEBUG_MEMORY
885 xmlGenericError(xmlGenericErrorContext,
886 "xmlMemSetup()\n");
887#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000888 if (freeFunc == NULL)
889 return(-1);
890 if (mallocFunc == NULL)
891 return(-1);
892 if (reallocFunc == NULL)
893 return(-1);
894 if (strdupFunc == NULL)
895 return(-1);
896 xmlFree = freeFunc;
897 xmlMalloc = mallocFunc;
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000898 xmlMallocAtomic = mallocFunc;
Owen Taylor3473f882001-02-23 17:55:21 +0000899 xmlRealloc = reallocFunc;
900 xmlMemStrdup = strdupFunc;
Daniel Veillardf93a8662004-07-01 12:56:30 +0000901#ifdef DEBUG_MEMORY
902 xmlGenericError(xmlGenericErrorContext,
903 "xmlMemSetup() Ok\n");
904#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000905 return(0);
906}
907
908/**
909 * xmlMemGet:
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000910 * @freeFunc: place to save the free() function in use
911 * @mallocFunc: place to save the malloc() function in use
912 * @reallocFunc: place to save the realloc() function in use
913 * @strdupFunc: place to save the strdup() function in use
Owen Taylor3473f882001-02-23 17:55:21 +0000914 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000915 * Provides the memory access functions set currently in use
Owen Taylor3473f882001-02-23 17:55:21 +0000916 *
917 * Returns 0 on success
918 */
919int
920xmlMemGet(xmlFreeFunc *freeFunc, xmlMallocFunc *mallocFunc,
921 xmlReallocFunc *reallocFunc, xmlStrdupFunc *strdupFunc) {
922 if (freeFunc != NULL) *freeFunc = xmlFree;
923 if (mallocFunc != NULL) *mallocFunc = xmlMalloc;
924 if (reallocFunc != NULL) *reallocFunc = xmlRealloc;
925 if (strdupFunc != NULL) *strdupFunc = xmlMemStrdup;
926 return(0);
927}
928
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000929/**
930 * xmlGcMemSetup:
931 * @freeFunc: the free() function to use
932 * @mallocFunc: the malloc() function to use
933 * @mallocAtomicFunc: the malloc() function to use for atomic allocations
934 * @reallocFunc: the realloc() function to use
935 * @strdupFunc: the strdup() function to use
936 *
937 * Override the default memory access functions with a new set
938 * This has to be called before any other libxml routines !
939 * The mallocAtomicFunc is specialized for atomic block
940 * allocations (i.e. of areas useful for garbage collected memory allocators
941 *
942 * Should this be blocked if there was already some allocations
943 * done ?
944 *
945 * Returns 0 on success
946 */
947int
948xmlGcMemSetup(xmlFreeFunc freeFunc, xmlMallocFunc mallocFunc,
949 xmlMallocFunc mallocAtomicFunc, xmlReallocFunc reallocFunc,
950 xmlStrdupFunc strdupFunc) {
Daniel Veillardf93a8662004-07-01 12:56:30 +0000951#ifdef DEBUG_MEMORY
952 xmlGenericError(xmlGenericErrorContext,
953 "xmlGcMemSetup()\n");
954#endif
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000955 if (freeFunc == NULL)
956 return(-1);
957 if (mallocFunc == NULL)
958 return(-1);
959 if (mallocAtomicFunc == NULL)
960 return(-1);
961 if (reallocFunc == NULL)
962 return(-1);
963 if (strdupFunc == NULL)
964 return(-1);
965 xmlFree = freeFunc;
966 xmlMalloc = mallocFunc;
967 xmlMallocAtomic = mallocAtomicFunc;
968 xmlRealloc = reallocFunc;
969 xmlMemStrdup = strdupFunc;
Daniel Veillardf93a8662004-07-01 12:56:30 +0000970#ifdef DEBUG_MEMORY
971 xmlGenericError(xmlGenericErrorContext,
972 "xmlGcMemSetup() Ok\n");
973#endif
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000974 return(0);
975}
976
977/**
978 * xmlGcMemGet:
979 * @freeFunc: place to save the free() function in use
980 * @mallocFunc: place to save the malloc() function in use
981 * @mallocAtomicFunc: place to save the atomic malloc() function in use
982 * @reallocFunc: place to save the realloc() function in use
983 * @strdupFunc: place to save the strdup() function in use
984 *
985 * Provides the memory access functions set currently in use
986 * The mallocAtomicFunc is specialized for atomic block
987 * allocations (i.e. of areas useful for garbage collected memory allocators
988 *
989 * Returns 0 on success
990 */
991int
992xmlGcMemGet(xmlFreeFunc *freeFunc, xmlMallocFunc *mallocFunc,
993 xmlMallocFunc *mallocAtomicFunc, xmlReallocFunc *reallocFunc,
994 xmlStrdupFunc *strdupFunc) {
995 if (freeFunc != NULL) *freeFunc = xmlFree;
996 if (mallocFunc != NULL) *mallocFunc = xmlMalloc;
997 if (mallocAtomicFunc != NULL) *mallocAtomicFunc = xmlMallocAtomic;
998 if (reallocFunc != NULL) *reallocFunc = xmlRealloc;
999 if (strdupFunc != NULL) *strdupFunc = xmlMemStrdup;
1000 return(0);
1001}
1002