blob: 927d078cc871e890fb6f85427b9e964ae35aeade [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 Veillard4432df22003-09-28 18:58:27 +000032
Daniel Veillard70cab352002-02-06 16:06:58 +000033/**
34 * MEM_LIST:
35 *
36 * keep track of all allocated blocks for error reporting
37 * Always build the memory list !
38 */
Daniel Veillardc064b472003-09-29 10:55:05 +000039#ifdef DEBUG_MEMORY_LOCATION
Daniel Veillard70cab352002-02-06 16:06:58 +000040#ifndef MEM_LIST
41#define MEM_LIST /* keep a list of all the allocated memory blocks */
42#endif
Daniel Veillardc064b472003-09-29 10:55:05 +000043#endif
Owen Taylor3473f882001-02-23 17:55:21 +000044
45#include <libxml/xmlmemory.h>
Daniel Veillardd0463562001-10-13 09:15:48 +000046#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000047#include <libxml/xmlerror.h>
William M. Brack0622fe82003-11-29 10:47:56 +000048#include <libxml/threads.h>
Owen Taylor3473f882001-02-23 17:55:21 +000049
Daniel Veillard4432df22003-09-28 18:58:27 +000050static int xmlMemInitialized = 0;
Daniel Veillardfb43bd62003-09-29 09:22:39 +000051static unsigned long debugMemSize = 0;
52static unsigned long debugMaxMemSize = 0;
William M. Brack0622fe82003-11-29 10:47:56 +000053static xmlMutexPtr xmlMemMutex = NULL;
Daniel Veillard4432df22003-09-28 18:58:27 +000054
Daniel Veillard56a4cb82001-03-24 17:00:36 +000055void xmlMallocBreakpoint(void);
Daniel Veillard56a4cb82001-03-24 17:00:36 +000056
57/************************************************************************
58 * *
59 * Macros, variables and associated types *
60 * *
61 ************************************************************************/
62
63
Owen Taylor3473f882001-02-23 17:55:21 +000064#ifdef xmlMalloc
65#undef xmlMalloc
66#endif
67#ifdef xmlRealloc
68#undef xmlRealloc
69#endif
70#ifdef xmlMemStrdup
71#undef xmlMemStrdup
72#endif
73
74
75/*
76 * Each of the blocks allocated begin with a header containing informations
77 */
78
79#define MEMTAG 0x5aa5
80
81#define MALLOC_TYPE 1
82#define REALLOC_TYPE 2
83#define STRDUP_TYPE 3
Daniel Veillard3c908dc2003-04-19 00:07:51 +000084#define MALLOC_ATOMIC_TYPE 4
85#define REALLOC_ATOMIC_TYPE 5
Owen Taylor3473f882001-02-23 17:55:21 +000086
87typedef struct memnod {
88 unsigned int mh_tag;
89 unsigned int mh_type;
90 unsigned long mh_number;
91 size_t mh_size;
92#ifdef MEM_LIST
93 struct memnod *mh_next;
94 struct memnod *mh_prev;
95#endif
96 const char *mh_file;
97 unsigned int mh_line;
98} MEMHDR;
99
100
101#ifdef SUN4
102#define ALIGN_SIZE 16
103#else
104#define ALIGN_SIZE sizeof(double)
105#endif
106#define HDR_SIZE sizeof(MEMHDR)
107#define RESERVE_SIZE (((HDR_SIZE + (ALIGN_SIZE-1)) \
108 / ALIGN_SIZE ) * ALIGN_SIZE)
109
110
111#define CLIENT_2_HDR(a) ((MEMHDR *) (((char *) (a)) - RESERVE_SIZE))
112#define HDR_2_CLIENT(a) ((void *) (((char *) (a)) + RESERVE_SIZE))
113
114
William M. Brack0622fe82003-11-29 10:47:56 +0000115static unsigned int block=0;
116static unsigned int xmlMemStopAtBlock = 0;
Daniel Veillardb44025c2001-10-11 22:55:55 +0000117static void *xmlMemTraceBlockAt = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +0000118#ifdef MEM_LIST
119static MEMHDR *memlist = NULL;
120#endif
121
Daniel Veillard01c13b52002-12-10 15:19:08 +0000122static void debugmem_tag_error(void *addr);
Owen Taylor3473f882001-02-23 17:55:21 +0000123#ifdef MEM_LIST
Daniel Veillard01c13b52002-12-10 15:19:08 +0000124static void debugmem_list_add(MEMHDR *);
125static void debugmem_list_delete(MEMHDR *);
Owen Taylor3473f882001-02-23 17:55:21 +0000126#endif
127#define Mem_Tag_Err(a) debugmem_tag_error(a);
128
129#ifndef TEST_POINT
130#define TEST_POINT
131#endif
132
133/**
134 * xmlMallocBreakpoint:
135 *
136 * Breakpoint to use in conjunction with xmlMemStopAtBlock. When the block
137 * number reaches the specified value this function is called. One need to add a breakpoint
138 * to it to get the context in which the given block is allocated.
139 */
140
141void
142xmlMallocBreakpoint(void) {
143 xmlGenericError(xmlGenericErrorContext,
144 "xmlMallocBreakpoint reached on block %d\n", xmlMemStopAtBlock);
145}
146
147/**
148 * xmlMallocLoc:
149 * @size: an int specifying the size in byte to allocate.
150 * @file: the file name or NULL
151 * @line: the line number
152 *
153 * a malloc() equivalent, with logging of the allocation info.
154 *
155 * Returns a pointer to the allocated area or NULL in case of lack of memory.
156 */
157
158void *
Daniel Veillard8599e702001-07-17 21:38:51 +0000159xmlMallocLoc(size_t size, const char * file, int line)
Owen Taylor3473f882001-02-23 17:55:21 +0000160{
161 MEMHDR *p;
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000162 void *ret;
Owen Taylor3473f882001-02-23 17:55:21 +0000163
164 if (!xmlMemInitialized) xmlInitMemory();
165#ifdef DEBUG_MEMORY
166 xmlGenericError(xmlGenericErrorContext,
167 "Malloc(%d)\n",size);
168#endif
169
170 TEST_POINT
171
172 p = (MEMHDR *) malloc(RESERVE_SIZE+size);
173
174 if (!p) {
175 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard26908ab2002-01-01 16:50:03 +0000176 "xmlMallocLoc : Out of free space\n");
Owen Taylor3473f882001-02-23 17:55:21 +0000177 xmlMemoryDump();
178 return(NULL);
179 }
180 p->mh_tag = MEMTAG;
Owen Taylor3473f882001-02-23 17:55:21 +0000181 p->mh_size = size;
182 p->mh_type = MALLOC_TYPE;
183 p->mh_file = file;
184 p->mh_line = line;
William M. Brack0622fe82003-11-29 10:47:56 +0000185 xmlMutexLock(xmlMemMutex);
186 p->mh_number = ++block;
Owen Taylor3473f882001-02-23 17:55:21 +0000187 debugMemSize += size;
188 if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
189#ifdef MEM_LIST
190 debugmem_list_add(p);
191#endif
William M. Brack0622fe82003-11-29 10:47:56 +0000192 xmlMutexUnlock(xmlMemMutex);
193
Owen Taylor3473f882001-02-23 17:55:21 +0000194#ifdef DEBUG_MEMORY
195 xmlGenericError(xmlGenericErrorContext,
196 "Malloc(%d) Ok\n",size);
197#endif
198
William M. Brack0622fe82003-11-29 10:47:56 +0000199 if (xmlMemStopAtBlock == p->mh_number) xmlMallocBreakpoint();
Owen Taylor3473f882001-02-23 17:55:21 +0000200
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000201 ret = HDR_2_CLIENT(p);
202
203 if (xmlMemTraceBlockAt == ret) {
204 xmlGenericError(xmlGenericErrorContext,
205 "%p : Malloc(%d) Ok\n", xmlMemTraceBlockAt, size);
206 xmlMallocBreakpoint();
207 }
208
Owen Taylor3473f882001-02-23 17:55:21 +0000209 TEST_POINT
210
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000211 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000212}
213
214/**
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000215 * xmlMallocAtomicLoc:
216 * @size: an int specifying the size in byte to allocate.
217 * @file: the file name or NULL
218 * @line: the line number
219 *
220 * a malloc() equivalent, with logging of the allocation info.
221 *
222 * Returns a pointer to the allocated area or NULL in case of lack of memory.
223 */
224
225void *
226xmlMallocAtomicLoc(size_t size, const char * file, int line)
227{
228 MEMHDR *p;
229 void *ret;
230
231 if (!xmlMemInitialized) xmlInitMemory();
232#ifdef DEBUG_MEMORY
233 xmlGenericError(xmlGenericErrorContext,
234 "Malloc(%d)\n",size);
235#endif
236
237 TEST_POINT
238
239 p = (MEMHDR *) malloc(RESERVE_SIZE+size);
240
241 if (!p) {
242 xmlGenericError(xmlGenericErrorContext,
243 "xmlMallocLoc : Out of free space\n");
244 xmlMemoryDump();
245 return(NULL);
246 }
247 p->mh_tag = MEMTAG;
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000248 p->mh_size = size;
249 p->mh_type = MALLOC_ATOMIC_TYPE;
250 p->mh_file = file;
251 p->mh_line = line;
William M. Brack0622fe82003-11-29 10:47:56 +0000252 xmlMutexLock(xmlMemMutex);
253 p->mh_number = ++block;
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000254 debugMemSize += size;
255 if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
256#ifdef MEM_LIST
257 debugmem_list_add(p);
258#endif
William M. Brack0622fe82003-11-29 10:47:56 +0000259 xmlMutexUnlock(xmlMemMutex);
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000260
261#ifdef DEBUG_MEMORY
262 xmlGenericError(xmlGenericErrorContext,
263 "Malloc(%d) Ok\n",size);
264#endif
265
William M. Brack0622fe82003-11-29 10:47:56 +0000266 if (xmlMemStopAtBlock == p->mh_number) xmlMallocBreakpoint();
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000267
268 ret = HDR_2_CLIENT(p);
269
270 if (xmlMemTraceBlockAt == ret) {
271 xmlGenericError(xmlGenericErrorContext,
272 "%p : Malloc(%d) Ok\n", xmlMemTraceBlockAt, size);
273 xmlMallocBreakpoint();
274 }
275
276 TEST_POINT
277
278 return(ret);
279}
280/**
Owen Taylor3473f882001-02-23 17:55:21 +0000281 * xmlMemMalloc:
282 * @size: an int specifying the size in byte to allocate.
283 *
284 * a malloc() equivalent, with logging of the allocation info.
285 *
286 * Returns a pointer to the allocated area or NULL in case of lack of memory.
287 */
288
289void *
Daniel Veillard8599e702001-07-17 21:38:51 +0000290xmlMemMalloc(size_t size)
Owen Taylor3473f882001-02-23 17:55:21 +0000291{
292 return(xmlMallocLoc(size, "none", 0));
293}
294
295/**
296 * xmlReallocLoc:
297 * @ptr: the initial memory block pointer
298 * @size: an int specifying the size in byte to allocate.
299 * @file: the file name or NULL
300 * @line: the line number
301 *
302 * a realloc() equivalent, with logging of the allocation info.
303 *
304 * Returns a pointer to the allocated area or NULL in case of lack of memory.
305 */
306
307void *
Daniel Veillard8599e702001-07-17 21:38:51 +0000308xmlReallocLoc(void *ptr,size_t size, const char * file, int line)
Owen Taylor3473f882001-02-23 17:55:21 +0000309{
310 MEMHDR *p;
311 unsigned long number;
312
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000313 if (ptr == NULL)
Aleksey Sanine9f08112004-01-22 22:20:31 +0000314 return(xmlMallocLoc(size, file, line));
315
316 if (!xmlMemInitialized) xmlInitMemory();
Owen Taylor3473f882001-02-23 17:55:21 +0000317 TEST_POINT
318
319 p = CLIENT_2_HDR(ptr);
320 number = p->mh_number;
321 if (p->mh_tag != MEMTAG) {
322 Mem_Tag_Err(p);
323 goto error;
324 }
325 p->mh_tag = ~MEMTAG;
William M. Brack0622fe82003-11-29 10:47:56 +0000326 xmlMutexLock(xmlMemMutex);
Owen Taylor3473f882001-02-23 17:55:21 +0000327 debugMemSize -= p->mh_size;
328#ifdef MEM_LIST
329 debugmem_list_delete(p);
330#endif
William M. Brack0622fe82003-11-29 10:47:56 +0000331 xmlMutexUnlock(xmlMemMutex);
332
Owen Taylor3473f882001-02-23 17:55:21 +0000333 p = (MEMHDR *) realloc(p,RESERVE_SIZE+size);
334 if (!p) {
335 goto error;
336 }
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000337 if (xmlMemTraceBlockAt == ptr) {
338 xmlGenericError(xmlGenericErrorContext,
339 "%p : Realloced(%d -> %d) Ok\n",
340 xmlMemTraceBlockAt, p->mh_size, size);
341 xmlMallocBreakpoint();
342 }
Owen Taylor3473f882001-02-23 17:55:21 +0000343 p->mh_tag = MEMTAG;
344 p->mh_number = number;
345 p->mh_type = REALLOC_TYPE;
346 p->mh_size = size;
347 p->mh_file = file;
348 p->mh_line = line;
William M. Brack0622fe82003-11-29 10:47:56 +0000349 xmlMutexLock(xmlMemMutex);
Owen Taylor3473f882001-02-23 17:55:21 +0000350 debugMemSize += size;
351 if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
352#ifdef MEM_LIST
353 debugmem_list_add(p);
354#endif
William M. Brack0622fe82003-11-29 10:47:56 +0000355 xmlMutexUnlock(xmlMemMutex);
Owen Taylor3473f882001-02-23 17:55:21 +0000356
357 TEST_POINT
358
359 return(HDR_2_CLIENT(p));
360
361error:
362 return(NULL);
363}
364
365/**
366 * xmlMemRealloc:
367 * @ptr: the initial memory block pointer
368 * @size: an int specifying the size in byte to allocate.
369 *
370 * a realloc() equivalent, with logging of the allocation info.
371 *
372 * Returns a pointer to the allocated area or NULL in case of lack of memory.
373 */
374
375void *
Daniel Veillard8599e702001-07-17 21:38:51 +0000376xmlMemRealloc(void *ptr,size_t size) {
Owen Taylor3473f882001-02-23 17:55:21 +0000377 return(xmlReallocLoc(ptr, size, "none", 0));
378}
379
380/**
381 * xmlMemFree:
382 * @ptr: the memory block pointer
383 *
384 * a free() equivalent, with error checking.
385 */
386void
387xmlMemFree(void *ptr)
388{
389 MEMHDR *p;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000390 char *target;
Owen Taylor3473f882001-02-23 17:55:21 +0000391
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000392 if (ptr == (void *) -1) {
393 xmlGenericError(xmlGenericErrorContext,
394 "trying to free pointer from freed area\n");
395 goto error;
396 }
397
398 if (xmlMemTraceBlockAt == ptr) {
399 xmlGenericError(xmlGenericErrorContext,
400 "%p : Freed()\n", xmlMemTraceBlockAt);
401 xmlMallocBreakpoint();
402 }
403
Owen Taylor3473f882001-02-23 17:55:21 +0000404 TEST_POINT
405
Daniel Veillard92ad2102001-03-27 12:47:33 +0000406 target = (char *) ptr;
407
Owen Taylor3473f882001-02-23 17:55:21 +0000408 p = CLIENT_2_HDR(ptr);
409 if (p->mh_tag != MEMTAG) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000410 Mem_Tag_Err(p);
411 goto error;
Owen Taylor3473f882001-02-23 17:55:21 +0000412 }
413 p->mh_tag = ~MEMTAG;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000414 memset(target, -1, p->mh_size);
William M. Brack0622fe82003-11-29 10:47:56 +0000415 xmlMutexLock(xmlMemMutex);
416 debugMemSize -= p->mh_size;
Owen Taylor3473f882001-02-23 17:55:21 +0000417#ifdef MEM_LIST
418 debugmem_list_delete(p);
419#endif
William M. Brack0622fe82003-11-29 10:47:56 +0000420 xmlMutexUnlock(xmlMemMutex);
421
Owen Taylor3473f882001-02-23 17:55:21 +0000422 free(p);
423
424 TEST_POINT
425
426 return;
427
428error:
429 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard26908ab2002-01-01 16:50:03 +0000430 "xmlMemFree(%lX) error\n", (unsigned long) ptr);
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000431 xmlMallocBreakpoint();
Owen Taylor3473f882001-02-23 17:55:21 +0000432 return;
433}
434
435/**
436 * xmlMemStrdupLoc:
Daniel Veillard9d06d302002-01-22 18:15:52 +0000437 * @str: the initial string pointer
Owen Taylor3473f882001-02-23 17:55:21 +0000438 * @file: the file name or NULL
439 * @line: the line number
440 *
441 * a strdup() equivalent, with logging of the allocation info.
442 *
Daniel Veillard26908ab2002-01-01 16:50:03 +0000443 * Returns a pointer to the new string or NULL if allocation error occurred.
Owen Taylor3473f882001-02-23 17:55:21 +0000444 */
445
446char *
447xmlMemStrdupLoc(const char *str, const char *file, int line)
448{
449 char *s;
450 size_t size = strlen(str) + 1;
451 MEMHDR *p;
452
453 if (!xmlMemInitialized) xmlInitMemory();
454 TEST_POINT
455
456 p = (MEMHDR *) malloc(RESERVE_SIZE+size);
457 if (!p) {
458 goto error;
459 }
460 p->mh_tag = MEMTAG;
Owen Taylor3473f882001-02-23 17:55:21 +0000461 p->mh_size = size;
462 p->mh_type = STRDUP_TYPE;
463 p->mh_file = file;
464 p->mh_line = line;
William M. Brack0622fe82003-11-29 10:47:56 +0000465 xmlMutexLock(xmlMemMutex);
466 p->mh_number = ++block;
Owen Taylor3473f882001-02-23 17:55:21 +0000467 debugMemSize += size;
468 if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
469#ifdef MEM_LIST
470 debugmem_list_add(p);
471#endif
William M. Brack0622fe82003-11-29 10:47:56 +0000472 xmlMutexUnlock(xmlMemMutex);
473
Owen Taylor3473f882001-02-23 17:55:21 +0000474 s = (char *) HDR_2_CLIENT(p);
475
William M. Brack0622fe82003-11-29 10:47:56 +0000476 if (xmlMemStopAtBlock == p->mh_number) xmlMallocBreakpoint();
Owen Taylor3473f882001-02-23 17:55:21 +0000477
478 if (s != NULL)
479 strcpy(s,str);
480 else
481 goto error;
482
483 TEST_POINT
484
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000485 if (xmlMemTraceBlockAt == s) {
486 xmlGenericError(xmlGenericErrorContext,
487 "%p : Strdup() Ok\n", xmlMemTraceBlockAt);
488 xmlMallocBreakpoint();
489 }
490
Owen Taylor3473f882001-02-23 17:55:21 +0000491 return(s);
492
493error:
494 return(NULL);
495}
496
497/**
498 * xmlMemoryStrdup:
Daniel Veillard01c13b52002-12-10 15:19:08 +0000499 * @str: the initial string pointer
Owen Taylor3473f882001-02-23 17:55:21 +0000500 *
501 * a strdup() equivalent, with logging of the allocation info.
502 *
Daniel Veillard26908ab2002-01-01 16:50:03 +0000503 * Returns a pointer to the new string or NULL if allocation error occurred.
Owen Taylor3473f882001-02-23 17:55:21 +0000504 */
505
506char *
507xmlMemoryStrdup(const char *str) {
508 return(xmlMemStrdupLoc(str, "none", 0));
509}
510
511/**
512 * xmlMemUsed:
513 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000514 * Provides the amount of memory currently allocated
Owen Taylor3473f882001-02-23 17:55:21 +0000515 *
516 * Returns an int representing the amount of memory allocated.
517 */
518
519int
520xmlMemUsed(void) {
521 return(debugMemSize);
522}
523
524#ifdef MEM_LIST
525/**
526 * xmlMemContentShow:
527 * @fp: a FILE descriptor used as the output file
528 * @p: a memory block header
529 *
530 * tries to show some content from the memory block
531 */
532
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000533static void
Owen Taylor3473f882001-02-23 17:55:21 +0000534xmlMemContentShow(FILE *fp, MEMHDR *p)
535{
536 int i,j,len = p->mh_size;
537 const char *buf = (const char *) HDR_2_CLIENT(p);
538
539 if (p == NULL) {
540 fprintf(fp, " NULL");
541 return;
542 }
543
544 for (i = 0;i < len;i++) {
545 if (buf[i] == 0) break;
Daniel Veillard9f28f302002-02-15 20:48:08 +0000546 if (!isprint((unsigned char) buf[i])) break;
Owen Taylor3473f882001-02-23 17:55:21 +0000547 }
548 if ((i < 4) && ((buf[i] != 0) || (i == 0))) {
549 if (len >= 4) {
550 MEMHDR *q;
551 void *cur;
552
553 for (j = 0;j < len -3;j += 4) {
554 cur = *((void **) &buf[j]);
555 q = CLIENT_2_HDR(cur);
556 p = memlist;
557 while (p != NULL) {
558 if (p == q) break;
559 p = p->mh_next;
560 }
561 if ((p != NULL) && (p == q)) {
562 fprintf(fp, " pointer to #%lu at index %d",
563 p->mh_number, j);
564 return;
565 }
566 }
567 }
568 } else if ((i == 0) && (buf[i] == 0)) {
569 fprintf(fp," null");
570 } else {
571 if (buf[i] == 0) fprintf(fp," \"%.25s\"", buf);
572 else {
573 fprintf(fp," [");
574 for (j = 0;j < i;j++)
575 fprintf(fp,"%c", buf[j]);
576 fprintf(fp,"]");
577 }
578 }
579}
580#endif
581
582/**
Owen Taylor3473f882001-02-23 17:55:21 +0000583 * xmlMemDisplay:
584 * @fp: a FILE descriptor used as the output file, if NULL, the result is
585 * written to the file .memorylist
586 *
587 * show in-extenso the memory blocks allocated
588 */
589
590void
591xmlMemDisplay(FILE *fp)
592{
593#ifdef MEM_LIST
594 MEMHDR *p;
Daniel Veillard144024e2002-02-13 21:14:46 +0000595 unsigned idx;
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000596 int nb = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000597#if defined(HAVE_LOCALTIME) && defined(HAVE_STRFTIME)
598 time_t currentTime;
599 char buf[500];
600 struct tm * tstruct;
601
602 currentTime = time(NULL);
603 tstruct = localtime(&currentTime);
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000604 strftime(buf, sizeof(buf) - 1, "%I:%M:%S %p", tstruct);
Owen Taylor3473f882001-02-23 17:55:21 +0000605 fprintf(fp," %s\n\n", buf);
606#endif
607
608
609 fprintf(fp," MEMORY ALLOCATED : %lu, MAX was %lu\n",
610 debugMemSize, debugMaxMemSize);
611 fprintf(fp,"BLOCK NUMBER SIZE TYPE\n");
612 idx = 0;
William M. Brack0622fe82003-11-29 10:47:56 +0000613 xmlMutexLock(xmlMemMutex);
Owen Taylor3473f882001-02-23 17:55:21 +0000614 p = memlist;
615 while (p) {
Daniel Veillard144024e2002-02-13 21:14:46 +0000616 fprintf(fp,"%-5u %6lu %6lu ",idx++,p->mh_number,
617 (unsigned long)p->mh_size);
Owen Taylor3473f882001-02-23 17:55:21 +0000618 switch (p->mh_type) {
619 case STRDUP_TYPE:fprintf(fp,"strdup() in ");break;
620 case MALLOC_TYPE:fprintf(fp,"malloc() in ");break;
621 case REALLOC_TYPE:fprintf(fp,"realloc() in ");break;
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000622 case MALLOC_ATOMIC_TYPE:fprintf(fp,"atomicmalloc() in ");break;
623 case REALLOC_ATOMIC_TYPE:fprintf(fp,"atomicrealloc() in ");break;
Owen Taylor3473f882001-02-23 17:55:21 +0000624 default:fprintf(fp," ??? in ");break;
625 }
626 if (p->mh_file != NULL) fprintf(fp,"%s(%d)", p->mh_file, p->mh_line);
627 if (p->mh_tag != MEMTAG)
628 fprintf(fp," INVALID");
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000629 nb++;
630 if (nb < 100)
631 xmlMemContentShow(fp, p);
632 else
633 fprintf(fp," skip");
634
Owen Taylor3473f882001-02-23 17:55:21 +0000635 fprintf(fp,"\n");
636 p = p->mh_next;
637 }
William M. Brack0622fe82003-11-29 10:47:56 +0000638 xmlMutexUnlock(xmlMemMutex);
Owen Taylor3473f882001-02-23 17:55:21 +0000639#else
640 fprintf(fp,"Memory list not compiled (MEM_LIST not defined !)\n");
641#endif
642}
643
644#ifdef MEM_LIST
645
Daniel Veillard01c13b52002-12-10 15:19:08 +0000646static void debugmem_list_add(MEMHDR *p)
Owen Taylor3473f882001-02-23 17:55:21 +0000647{
648 p->mh_next = memlist;
649 p->mh_prev = NULL;
650 if (memlist) memlist->mh_prev = p;
651 memlist = p;
652#ifdef MEM_LIST_DEBUG
653 if (stderr)
654 Mem_Display(stderr);
655#endif
656}
657
Daniel Veillard01c13b52002-12-10 15:19:08 +0000658static void debugmem_list_delete(MEMHDR *p)
Owen Taylor3473f882001-02-23 17:55:21 +0000659{
660 if (p->mh_next)
661 p->mh_next->mh_prev = p->mh_prev;
662 if (p->mh_prev)
663 p->mh_prev->mh_next = p->mh_next;
664 else memlist = p->mh_next;
665#ifdef MEM_LIST_DEBUG
666 if (stderr)
667 Mem_Display(stderr);
668#endif
669}
670
671#endif
672
673/*
Daniel Veillard01c13b52002-12-10 15:19:08 +0000674 * debugmem_tag_error:
675 *
676 * internal error function.
Owen Taylor3473f882001-02-23 17:55:21 +0000677 */
678
Daniel Veillard01c13b52002-12-10 15:19:08 +0000679static void debugmem_tag_error(void *p)
Owen Taylor3473f882001-02-23 17:55:21 +0000680{
681 xmlGenericError(xmlGenericErrorContext,
682 "Memory tag error occurs :%p \n\t bye\n", p);
683#ifdef MEM_LIST
684 if (stderr)
685 xmlMemDisplay(stderr);
686#endif
687}
688
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000689#ifdef MEM_LIST
Daniel Veillardb44025c2001-10-11 22:55:55 +0000690static FILE *xmlMemoryDumpFile = NULL;
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000691#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000692
Owen Taylor3473f882001-02-23 17:55:21 +0000693/**
Daniel Veillardfb43bd62003-09-29 09:22:39 +0000694 * xmlMemShow:
695 * @fp: a FILE descriptor used as the output file
696 * @nr: number of entries to dump
697 *
698 * show a show display of the memory allocated, and dump
699 * the @nr last allocated areas which were not freed
700 */
701
702void
Daniel Veillardc064b472003-09-29 10:55:05 +0000703xmlMemShow(FILE *fp, int nr ATTRIBUTE_UNUSED)
Daniel Veillardfb43bd62003-09-29 09:22:39 +0000704{
Daniel Veillardfb43bd62003-09-29 09:22:39 +0000705#ifdef MEM_LIST
706 MEMHDR *p;
707#endif
Daniel Veillardfb43bd62003-09-29 09:22:39 +0000708
709 if (fp != NULL)
710 fprintf(fp," MEMORY ALLOCATED : %lu, MAX was %lu\n",
711 debugMemSize, debugMaxMemSize);
Daniel Veillardfb43bd62003-09-29 09:22:39 +0000712#ifdef MEM_LIST
William M. Brack0622fe82003-11-29 10:47:56 +0000713 xmlMutexLock(xmlMemMutex);
Daniel Veillardfb43bd62003-09-29 09:22:39 +0000714 if (nr > 0) {
715 fprintf(fp,"NUMBER SIZE TYPE WHERE\n");
716 p = memlist;
717 while ((p) && nr > 0) {
718 fprintf(fp,"%6lu %6lu ",p->mh_number,(unsigned long)p->mh_size);
719 switch (p->mh_type) {
720 case STRDUP_TYPE:fprintf(fp,"strdup() in ");break;
721 case MALLOC_TYPE:fprintf(fp,"malloc() in ");break;
722 case MALLOC_ATOMIC_TYPE:fprintf(fp,"atomicmalloc() in ");break;
723 case REALLOC_TYPE:fprintf(fp,"realloc() in ");break;
724 case REALLOC_ATOMIC_TYPE:fprintf(fp,"atomicrealloc() in ");break;
725 default:fprintf(fp," ??? in ");break;
726 }
727 if (p->mh_file != NULL)
728 fprintf(fp,"%s(%d)", p->mh_file, p->mh_line);
729 if (p->mh_tag != MEMTAG)
730 fprintf(fp," INVALID");
731 xmlMemContentShow(fp, p);
732 fprintf(fp,"\n");
733 nr--;
734 p = p->mh_next;
735 }
736 }
William M. Brack0622fe82003-11-29 10:47:56 +0000737 xmlMutexUnlock(xmlMemMutex);
Daniel Veillardfb43bd62003-09-29 09:22:39 +0000738#endif /* MEM_LIST */
Daniel Veillardfb43bd62003-09-29 09:22:39 +0000739}
740
741/**
Owen Taylor3473f882001-02-23 17:55:21 +0000742 * xmlMemoryDump:
743 *
744 * Dump in-extenso the memory blocks allocated to the file .memorylist
745 */
746
747void
748xmlMemoryDump(void)
749{
Daniel Veillardc064b472003-09-29 10:55:05 +0000750#ifdef MEM_LIST
Owen Taylor3473f882001-02-23 17:55:21 +0000751 FILE *dump;
752
Daniel Veillard5997aca2002-03-18 18:36:20 +0000753 if (debugMaxMemSize == 0)
754 return;
Owen Taylor3473f882001-02-23 17:55:21 +0000755 dump = fopen(".memdump", "w");
Daniel Veillardcd337f02001-11-22 18:20:37 +0000756 if (dump == NULL)
757 xmlMemoryDumpFile = stderr;
Owen Taylor3473f882001-02-23 17:55:21 +0000758 else xmlMemoryDumpFile = dump;
759
760 xmlMemDisplay(xmlMemoryDumpFile);
761
762 if (dump != NULL) fclose(dump);
Daniel Veillardc064b472003-09-29 10:55:05 +0000763#endif /* MEM_LIST */
Owen Taylor3473f882001-02-23 17:55:21 +0000764}
765
766
767/****************************************************************
768 * *
769 * Initialization Routines *
770 * *
771 ****************************************************************/
772
Owen Taylor3473f882001-02-23 17:55:21 +0000773/**
774 * xmlInitMemory:
775 *
776 * Initialize the memory layer.
777 *
778 * Returns 0 on success
779 */
Owen Taylor3473f882001-02-23 17:55:21 +0000780int
781xmlInitMemory(void)
782{
Owen Taylor3473f882001-02-23 17:55:21 +0000783#ifdef HAVE_STDLIB_H
784 char *breakpoint;
785#endif
William M. Brack92029422004-01-04 01:01:14 +0000786 /*
787 This is really not good code (see Bug 130419). Suggestions for
788 improvement will be welcome!
789 */
790 if (xmlMemInitialized) return(-1);
William M. Brack0622fe82003-11-29 10:47:56 +0000791 xmlMemInitialized = 1;
William M. Brack0622fe82003-11-29 10:47:56 +0000792 xmlMemMutex = xmlNewMutex();
Owen Taylor3473f882001-02-23 17:55:21 +0000793
794#ifdef HAVE_STDLIB_H
795 breakpoint = getenv("XML_MEM_BREAKPOINT");
796 if (breakpoint != NULL) {
William M. Brack0622fe82003-11-29 10:47:56 +0000797 sscanf(breakpoint, "%ud", &xmlMemStopAtBlock);
Owen Taylor3473f882001-02-23 17:55:21 +0000798 }
799#endif
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000800#ifdef HAVE_STDLIB_H
801 breakpoint = getenv("XML_MEM_TRACE");
802 if (breakpoint != NULL) {
803 sscanf(breakpoint, "%p", &xmlMemTraceBlockAt);
804 }
805#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000806
807#ifdef DEBUG_MEMORY
808 xmlGenericError(xmlGenericErrorContext,
809 "xmlInitMemory() Ok\n");
810#endif
Daniel Veillardd30be4a2002-03-28 18:25:31 +0000811
Daniel Veillard4432df22003-09-28 18:58:27 +0000812 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +0000813}
814
815/**
William M. Brack72ee48d2003-12-30 08:30:19 +0000816 * xmlCleanupMemory:
817 *
818 * Free up all the memory associated with memorys
819 */
820void
821xmlCleanupMemory(void) {
822 if (xmlMemInitialized == 0)
823 return;
824
825 xmlFreeMutex(xmlMemMutex);
Daniel Veillard1a9b7082004-01-02 10:42:01 +0000826 xmlMemMutex = NULL;
William M. Brack72ee48d2003-12-30 08:30:19 +0000827 xmlMemInitialized = 0;
828}
829
830/**
Owen Taylor3473f882001-02-23 17:55:21 +0000831 * xmlMemSetup:
832 * @freeFunc: the free() function to use
833 * @mallocFunc: the malloc() function to use
834 * @reallocFunc: the realloc() function to use
835 * @strdupFunc: the strdup() function to use
836 *
837 * Override the default memory access functions with a new set
838 * This has to be called before any other libxml routines !
839 *
840 * Should this be blocked if there was already some allocations
841 * done ?
842 *
843 * Returns 0 on success
844 */
845int
846xmlMemSetup(xmlFreeFunc freeFunc, xmlMallocFunc mallocFunc,
847 xmlReallocFunc reallocFunc, xmlStrdupFunc strdupFunc) {
848 if (freeFunc == NULL)
849 return(-1);
850 if (mallocFunc == NULL)
851 return(-1);
852 if (reallocFunc == NULL)
853 return(-1);
854 if (strdupFunc == NULL)
855 return(-1);
856 xmlFree = freeFunc;
857 xmlMalloc = mallocFunc;
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000858 xmlMallocAtomic = mallocFunc;
Owen Taylor3473f882001-02-23 17:55:21 +0000859 xmlRealloc = reallocFunc;
860 xmlMemStrdup = strdupFunc;
861 return(0);
862}
863
864/**
865 * xmlMemGet:
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000866 * @freeFunc: place to save the free() function in use
867 * @mallocFunc: place to save the malloc() function in use
868 * @reallocFunc: place to save the realloc() function in use
869 * @strdupFunc: place to save the strdup() function in use
Owen Taylor3473f882001-02-23 17:55:21 +0000870 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000871 * Provides the memory access functions set currently in use
Owen Taylor3473f882001-02-23 17:55:21 +0000872 *
873 * Returns 0 on success
874 */
875int
876xmlMemGet(xmlFreeFunc *freeFunc, xmlMallocFunc *mallocFunc,
877 xmlReallocFunc *reallocFunc, xmlStrdupFunc *strdupFunc) {
878 if (freeFunc != NULL) *freeFunc = xmlFree;
879 if (mallocFunc != NULL) *mallocFunc = xmlMalloc;
880 if (reallocFunc != NULL) *reallocFunc = xmlRealloc;
881 if (strdupFunc != NULL) *strdupFunc = xmlMemStrdup;
882 return(0);
883}
884
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000885/**
886 * xmlGcMemSetup:
887 * @freeFunc: the free() function to use
888 * @mallocFunc: the malloc() function to use
889 * @mallocAtomicFunc: the malloc() function to use for atomic allocations
890 * @reallocFunc: the realloc() function to use
891 * @strdupFunc: the strdup() function to use
892 *
893 * Override the default memory access functions with a new set
894 * This has to be called before any other libxml routines !
895 * The mallocAtomicFunc is specialized for atomic block
896 * allocations (i.e. of areas useful for garbage collected memory allocators
897 *
898 * Should this be blocked if there was already some allocations
899 * done ?
900 *
901 * Returns 0 on success
902 */
903int
904xmlGcMemSetup(xmlFreeFunc freeFunc, xmlMallocFunc mallocFunc,
905 xmlMallocFunc mallocAtomicFunc, xmlReallocFunc reallocFunc,
906 xmlStrdupFunc strdupFunc) {
907 if (freeFunc == NULL)
908 return(-1);
909 if (mallocFunc == NULL)
910 return(-1);
911 if (mallocAtomicFunc == NULL)
912 return(-1);
913 if (reallocFunc == NULL)
914 return(-1);
915 if (strdupFunc == NULL)
916 return(-1);
917 xmlFree = freeFunc;
918 xmlMalloc = mallocFunc;
919 xmlMallocAtomic = mallocAtomicFunc;
920 xmlRealloc = reallocFunc;
921 xmlMemStrdup = strdupFunc;
922 return(0);
923}
924
925/**
926 * xmlGcMemGet:
927 * @freeFunc: place to save the free() function in use
928 * @mallocFunc: place to save the malloc() function in use
929 * @mallocAtomicFunc: place to save the atomic malloc() function in use
930 * @reallocFunc: place to save the realloc() function in use
931 * @strdupFunc: place to save the strdup() function in use
932 *
933 * Provides the memory access functions set currently in use
934 * The mallocAtomicFunc is specialized for atomic block
935 * allocations (i.e. of areas useful for garbage collected memory allocators
936 *
937 * Returns 0 on success
938 */
939int
940xmlGcMemGet(xmlFreeFunc *freeFunc, xmlMallocFunc *mallocFunc,
941 xmlMallocFunc *mallocAtomicFunc, xmlReallocFunc *reallocFunc,
942 xmlStrdupFunc *strdupFunc) {
943 if (freeFunc != NULL) *freeFunc = xmlFree;
944 if (mallocFunc != NULL) *mallocFunc = xmlMalloc;
945 if (mallocAtomicFunc != NULL) *mallocAtomicFunc = xmlMallocAtomic;
946 if (reallocFunc != NULL) *reallocFunc = xmlRealloc;
947 if (strdupFunc != NULL) *strdupFunc = xmlMemStrdup;
948 return(0);
949}
950