blob: 712a967f37bbe1bd0bac904d99f941c555f1ad4d [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
313 if (!xmlMemInitialized) xmlInitMemory();
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000314 if (ptr == NULL)
315 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000316 TEST_POINT
317
318 p = CLIENT_2_HDR(ptr);
319 number = p->mh_number;
320 if (p->mh_tag != MEMTAG) {
321 Mem_Tag_Err(p);
322 goto error;
323 }
324 p->mh_tag = ~MEMTAG;
William M. Brack0622fe82003-11-29 10:47:56 +0000325 xmlMutexLock(xmlMemMutex);
Owen Taylor3473f882001-02-23 17:55:21 +0000326 debugMemSize -= p->mh_size;
327#ifdef MEM_LIST
328 debugmem_list_delete(p);
329#endif
William M. Brack0622fe82003-11-29 10:47:56 +0000330 xmlMutexUnlock(xmlMemMutex);
331
Owen Taylor3473f882001-02-23 17:55:21 +0000332 p = (MEMHDR *) realloc(p,RESERVE_SIZE+size);
333 if (!p) {
334 goto error;
335 }
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000336 if (xmlMemTraceBlockAt == ptr) {
337 xmlGenericError(xmlGenericErrorContext,
338 "%p : Realloced(%d -> %d) Ok\n",
339 xmlMemTraceBlockAt, p->mh_size, size);
340 xmlMallocBreakpoint();
341 }
Owen Taylor3473f882001-02-23 17:55:21 +0000342 p->mh_tag = MEMTAG;
343 p->mh_number = number;
344 p->mh_type = REALLOC_TYPE;
345 p->mh_size = size;
346 p->mh_file = file;
347 p->mh_line = line;
William M. Brack0622fe82003-11-29 10:47:56 +0000348 xmlMutexLock(xmlMemMutex);
Owen Taylor3473f882001-02-23 17:55:21 +0000349 debugMemSize += size;
350 if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
351#ifdef MEM_LIST
352 debugmem_list_add(p);
353#endif
William M. Brack0622fe82003-11-29 10:47:56 +0000354 xmlMutexUnlock(xmlMemMutex);
Owen Taylor3473f882001-02-23 17:55:21 +0000355
356 TEST_POINT
357
358 return(HDR_2_CLIENT(p));
359
360error:
361 return(NULL);
362}
363
364/**
365 * xmlMemRealloc:
366 * @ptr: the initial memory block pointer
367 * @size: an int specifying the size in byte to allocate.
368 *
369 * a realloc() equivalent, with logging of the allocation info.
370 *
371 * Returns a pointer to the allocated area or NULL in case of lack of memory.
372 */
373
374void *
Daniel Veillard8599e702001-07-17 21:38:51 +0000375xmlMemRealloc(void *ptr,size_t size) {
Owen Taylor3473f882001-02-23 17:55:21 +0000376 return(xmlReallocLoc(ptr, size, "none", 0));
377}
378
379/**
380 * xmlMemFree:
381 * @ptr: the memory block pointer
382 *
383 * a free() equivalent, with error checking.
384 */
385void
386xmlMemFree(void *ptr)
387{
388 MEMHDR *p;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000389 char *target;
Owen Taylor3473f882001-02-23 17:55:21 +0000390
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000391 if (ptr == (void *) -1) {
392 xmlGenericError(xmlGenericErrorContext,
393 "trying to free pointer from freed area\n");
394 goto error;
395 }
396
397 if (xmlMemTraceBlockAt == ptr) {
398 xmlGenericError(xmlGenericErrorContext,
399 "%p : Freed()\n", xmlMemTraceBlockAt);
400 xmlMallocBreakpoint();
401 }
402
Owen Taylor3473f882001-02-23 17:55:21 +0000403 TEST_POINT
404
Daniel Veillard92ad2102001-03-27 12:47:33 +0000405 target = (char *) ptr;
406
Owen Taylor3473f882001-02-23 17:55:21 +0000407 p = CLIENT_2_HDR(ptr);
408 if (p->mh_tag != MEMTAG) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000409 Mem_Tag_Err(p);
410 goto error;
Owen Taylor3473f882001-02-23 17:55:21 +0000411 }
412 p->mh_tag = ~MEMTAG;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000413 memset(target, -1, p->mh_size);
William M. Brack0622fe82003-11-29 10:47:56 +0000414 xmlMutexLock(xmlMemMutex);
415 debugMemSize -= p->mh_size;
Owen Taylor3473f882001-02-23 17:55:21 +0000416#ifdef MEM_LIST
417 debugmem_list_delete(p);
418#endif
William M. Brack0622fe82003-11-29 10:47:56 +0000419 xmlMutexUnlock(xmlMemMutex);
420
Owen Taylor3473f882001-02-23 17:55:21 +0000421 free(p);
422
423 TEST_POINT
424
425 return;
426
427error:
428 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard26908ab2002-01-01 16:50:03 +0000429 "xmlMemFree(%lX) error\n", (unsigned long) ptr);
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000430 xmlMallocBreakpoint();
Owen Taylor3473f882001-02-23 17:55:21 +0000431 return;
432}
433
434/**
435 * xmlMemStrdupLoc:
Daniel Veillard9d06d302002-01-22 18:15:52 +0000436 * @str: the initial string pointer
Owen Taylor3473f882001-02-23 17:55:21 +0000437 * @file: the file name or NULL
438 * @line: the line number
439 *
440 * a strdup() equivalent, with logging of the allocation info.
441 *
Daniel Veillard26908ab2002-01-01 16:50:03 +0000442 * Returns a pointer to the new string or NULL if allocation error occurred.
Owen Taylor3473f882001-02-23 17:55:21 +0000443 */
444
445char *
446xmlMemStrdupLoc(const char *str, const char *file, int line)
447{
448 char *s;
449 size_t size = strlen(str) + 1;
450 MEMHDR *p;
451
452 if (!xmlMemInitialized) xmlInitMemory();
453 TEST_POINT
454
455 p = (MEMHDR *) malloc(RESERVE_SIZE+size);
456 if (!p) {
457 goto error;
458 }
459 p->mh_tag = MEMTAG;
Owen Taylor3473f882001-02-23 17:55:21 +0000460 p->mh_size = size;
461 p->mh_type = STRDUP_TYPE;
462 p->mh_file = file;
463 p->mh_line = line;
William M. Brack0622fe82003-11-29 10:47:56 +0000464 xmlMutexLock(xmlMemMutex);
465 p->mh_number = ++block;
Owen Taylor3473f882001-02-23 17:55:21 +0000466 debugMemSize += size;
467 if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
468#ifdef MEM_LIST
469 debugmem_list_add(p);
470#endif
William M. Brack0622fe82003-11-29 10:47:56 +0000471 xmlMutexUnlock(xmlMemMutex);
472
Owen Taylor3473f882001-02-23 17:55:21 +0000473 s = (char *) HDR_2_CLIENT(p);
474
William M. Brack0622fe82003-11-29 10:47:56 +0000475 if (xmlMemStopAtBlock == p->mh_number) xmlMallocBreakpoint();
Owen Taylor3473f882001-02-23 17:55:21 +0000476
477 if (s != NULL)
478 strcpy(s,str);
479 else
480 goto error;
481
482 TEST_POINT
483
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000484 if (xmlMemTraceBlockAt == s) {
485 xmlGenericError(xmlGenericErrorContext,
486 "%p : Strdup() Ok\n", xmlMemTraceBlockAt);
487 xmlMallocBreakpoint();
488 }
489
Owen Taylor3473f882001-02-23 17:55:21 +0000490 return(s);
491
492error:
493 return(NULL);
494}
495
496/**
497 * xmlMemoryStrdup:
Daniel Veillard01c13b52002-12-10 15:19:08 +0000498 * @str: the initial string pointer
Owen Taylor3473f882001-02-23 17:55:21 +0000499 *
500 * a strdup() equivalent, with logging of the allocation info.
501 *
Daniel Veillard26908ab2002-01-01 16:50:03 +0000502 * Returns a pointer to the new string or NULL if allocation error occurred.
Owen Taylor3473f882001-02-23 17:55:21 +0000503 */
504
505char *
506xmlMemoryStrdup(const char *str) {
507 return(xmlMemStrdupLoc(str, "none", 0));
508}
509
510/**
511 * xmlMemUsed:
512 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000513 * Provides the amount of memory currently allocated
Owen Taylor3473f882001-02-23 17:55:21 +0000514 *
515 * Returns an int representing the amount of memory allocated.
516 */
517
518int
519xmlMemUsed(void) {
520 return(debugMemSize);
521}
522
523#ifdef MEM_LIST
524/**
525 * xmlMemContentShow:
526 * @fp: a FILE descriptor used as the output file
527 * @p: a memory block header
528 *
529 * tries to show some content from the memory block
530 */
531
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000532static void
Owen Taylor3473f882001-02-23 17:55:21 +0000533xmlMemContentShow(FILE *fp, MEMHDR *p)
534{
535 int i,j,len = p->mh_size;
536 const char *buf = (const char *) HDR_2_CLIENT(p);
537
538 if (p == NULL) {
539 fprintf(fp, " NULL");
540 return;
541 }
542
543 for (i = 0;i < len;i++) {
544 if (buf[i] == 0) break;
Daniel Veillard9f28f302002-02-15 20:48:08 +0000545 if (!isprint((unsigned char) buf[i])) break;
Owen Taylor3473f882001-02-23 17:55:21 +0000546 }
547 if ((i < 4) && ((buf[i] != 0) || (i == 0))) {
548 if (len >= 4) {
549 MEMHDR *q;
550 void *cur;
551
552 for (j = 0;j < len -3;j += 4) {
553 cur = *((void **) &buf[j]);
554 q = CLIENT_2_HDR(cur);
555 p = memlist;
556 while (p != NULL) {
557 if (p == q) break;
558 p = p->mh_next;
559 }
560 if ((p != NULL) && (p == q)) {
561 fprintf(fp, " pointer to #%lu at index %d",
562 p->mh_number, j);
563 return;
564 }
565 }
566 }
567 } else if ((i == 0) && (buf[i] == 0)) {
568 fprintf(fp," null");
569 } else {
570 if (buf[i] == 0) fprintf(fp," \"%.25s\"", buf);
571 else {
572 fprintf(fp," [");
573 for (j = 0;j < i;j++)
574 fprintf(fp,"%c", buf[j]);
575 fprintf(fp,"]");
576 }
577 }
578}
579#endif
580
581/**
Owen Taylor3473f882001-02-23 17:55:21 +0000582 * xmlMemDisplay:
583 * @fp: a FILE descriptor used as the output file, if NULL, the result is
584 * written to the file .memorylist
585 *
586 * show in-extenso the memory blocks allocated
587 */
588
589void
590xmlMemDisplay(FILE *fp)
591{
592#ifdef MEM_LIST
593 MEMHDR *p;
Daniel Veillard144024e2002-02-13 21:14:46 +0000594 unsigned idx;
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000595 int nb = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000596#if defined(HAVE_LOCALTIME) && defined(HAVE_STRFTIME)
597 time_t currentTime;
598 char buf[500];
599 struct tm * tstruct;
600
601 currentTime = time(NULL);
602 tstruct = localtime(&currentTime);
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000603 strftime(buf, sizeof(buf) - 1, "%I:%M:%S %p", tstruct);
Owen Taylor3473f882001-02-23 17:55:21 +0000604 fprintf(fp," %s\n\n", buf);
605#endif
606
607
608 fprintf(fp," MEMORY ALLOCATED : %lu, MAX was %lu\n",
609 debugMemSize, debugMaxMemSize);
610 fprintf(fp,"BLOCK NUMBER SIZE TYPE\n");
611 idx = 0;
William M. Brack0622fe82003-11-29 10:47:56 +0000612 xmlMutexLock(xmlMemMutex);
Owen Taylor3473f882001-02-23 17:55:21 +0000613 p = memlist;
614 while (p) {
Daniel Veillard144024e2002-02-13 21:14:46 +0000615 fprintf(fp,"%-5u %6lu %6lu ",idx++,p->mh_number,
616 (unsigned long)p->mh_size);
Owen Taylor3473f882001-02-23 17:55:21 +0000617 switch (p->mh_type) {
618 case STRDUP_TYPE:fprintf(fp,"strdup() in ");break;
619 case MALLOC_TYPE:fprintf(fp,"malloc() in ");break;
620 case REALLOC_TYPE:fprintf(fp,"realloc() in ");break;
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000621 case MALLOC_ATOMIC_TYPE:fprintf(fp,"atomicmalloc() in ");break;
622 case REALLOC_ATOMIC_TYPE:fprintf(fp,"atomicrealloc() in ");break;
Owen Taylor3473f882001-02-23 17:55:21 +0000623 default:fprintf(fp," ??? in ");break;
624 }
625 if (p->mh_file != NULL) fprintf(fp,"%s(%d)", p->mh_file, p->mh_line);
626 if (p->mh_tag != MEMTAG)
627 fprintf(fp," INVALID");
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000628 nb++;
629 if (nb < 100)
630 xmlMemContentShow(fp, p);
631 else
632 fprintf(fp," skip");
633
Owen Taylor3473f882001-02-23 17:55:21 +0000634 fprintf(fp,"\n");
635 p = p->mh_next;
636 }
William M. Brack0622fe82003-11-29 10:47:56 +0000637 xmlMutexUnlock(xmlMemMutex);
Owen Taylor3473f882001-02-23 17:55:21 +0000638#else
639 fprintf(fp,"Memory list not compiled (MEM_LIST not defined !)\n");
640#endif
641}
642
643#ifdef MEM_LIST
644
Daniel Veillard01c13b52002-12-10 15:19:08 +0000645static void debugmem_list_add(MEMHDR *p)
Owen Taylor3473f882001-02-23 17:55:21 +0000646{
647 p->mh_next = memlist;
648 p->mh_prev = NULL;
649 if (memlist) memlist->mh_prev = p;
650 memlist = p;
651#ifdef MEM_LIST_DEBUG
652 if (stderr)
653 Mem_Display(stderr);
654#endif
655}
656
Daniel Veillard01c13b52002-12-10 15:19:08 +0000657static void debugmem_list_delete(MEMHDR *p)
Owen Taylor3473f882001-02-23 17:55:21 +0000658{
659 if (p->mh_next)
660 p->mh_next->mh_prev = p->mh_prev;
661 if (p->mh_prev)
662 p->mh_prev->mh_next = p->mh_next;
663 else memlist = p->mh_next;
664#ifdef MEM_LIST_DEBUG
665 if (stderr)
666 Mem_Display(stderr);
667#endif
668}
669
670#endif
671
672/*
Daniel Veillard01c13b52002-12-10 15:19:08 +0000673 * debugmem_tag_error:
674 *
675 * internal error function.
Owen Taylor3473f882001-02-23 17:55:21 +0000676 */
677
Daniel Veillard01c13b52002-12-10 15:19:08 +0000678static void debugmem_tag_error(void *p)
Owen Taylor3473f882001-02-23 17:55:21 +0000679{
680 xmlGenericError(xmlGenericErrorContext,
681 "Memory tag error occurs :%p \n\t bye\n", p);
682#ifdef MEM_LIST
683 if (stderr)
684 xmlMemDisplay(stderr);
685#endif
686}
687
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000688#ifdef MEM_LIST
Daniel Veillardb44025c2001-10-11 22:55:55 +0000689static FILE *xmlMemoryDumpFile = NULL;
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000690#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000691
Owen Taylor3473f882001-02-23 17:55:21 +0000692/**
Daniel Veillardfb43bd62003-09-29 09:22:39 +0000693 * xmlMemShow:
694 * @fp: a FILE descriptor used as the output file
695 * @nr: number of entries to dump
696 *
697 * show a show display of the memory allocated, and dump
698 * the @nr last allocated areas which were not freed
699 */
700
701void
Daniel Veillardc064b472003-09-29 10:55:05 +0000702xmlMemShow(FILE *fp, int nr ATTRIBUTE_UNUSED)
Daniel Veillardfb43bd62003-09-29 09:22:39 +0000703{
Daniel Veillardfb43bd62003-09-29 09:22:39 +0000704#ifdef MEM_LIST
705 MEMHDR *p;
706#endif
Daniel Veillardfb43bd62003-09-29 09:22:39 +0000707
708 if (fp != NULL)
709 fprintf(fp," MEMORY ALLOCATED : %lu, MAX was %lu\n",
710 debugMemSize, debugMaxMemSize);
Daniel Veillardfb43bd62003-09-29 09:22:39 +0000711#ifdef MEM_LIST
William M. Brack0622fe82003-11-29 10:47:56 +0000712 xmlMutexLock(xmlMemMutex);
Daniel Veillardfb43bd62003-09-29 09:22:39 +0000713 if (nr > 0) {
714 fprintf(fp,"NUMBER SIZE TYPE WHERE\n");
715 p = memlist;
716 while ((p) && nr > 0) {
717 fprintf(fp,"%6lu %6lu ",p->mh_number,(unsigned long)p->mh_size);
718 switch (p->mh_type) {
719 case STRDUP_TYPE:fprintf(fp,"strdup() in ");break;
720 case MALLOC_TYPE:fprintf(fp,"malloc() in ");break;
721 case MALLOC_ATOMIC_TYPE:fprintf(fp,"atomicmalloc() in ");break;
722 case REALLOC_TYPE:fprintf(fp,"realloc() in ");break;
723 case REALLOC_ATOMIC_TYPE:fprintf(fp,"atomicrealloc() in ");break;
724 default:fprintf(fp," ??? in ");break;
725 }
726 if (p->mh_file != NULL)
727 fprintf(fp,"%s(%d)", p->mh_file, p->mh_line);
728 if (p->mh_tag != MEMTAG)
729 fprintf(fp," INVALID");
730 xmlMemContentShow(fp, p);
731 fprintf(fp,"\n");
732 nr--;
733 p = p->mh_next;
734 }
735 }
William M. Brack0622fe82003-11-29 10:47:56 +0000736 xmlMutexUnlock(xmlMemMutex);
Daniel Veillardfb43bd62003-09-29 09:22:39 +0000737#endif /* MEM_LIST */
Daniel Veillardfb43bd62003-09-29 09:22:39 +0000738}
739
740/**
Owen Taylor3473f882001-02-23 17:55:21 +0000741 * xmlMemoryDump:
742 *
743 * Dump in-extenso the memory blocks allocated to the file .memorylist
744 */
745
746void
747xmlMemoryDump(void)
748{
Daniel Veillardc064b472003-09-29 10:55:05 +0000749#ifdef MEM_LIST
Owen Taylor3473f882001-02-23 17:55:21 +0000750 FILE *dump;
751
Daniel Veillard5997aca2002-03-18 18:36:20 +0000752 if (debugMaxMemSize == 0)
753 return;
Owen Taylor3473f882001-02-23 17:55:21 +0000754 dump = fopen(".memdump", "w");
Daniel Veillardcd337f02001-11-22 18:20:37 +0000755 if (dump == NULL)
756 xmlMemoryDumpFile = stderr;
Owen Taylor3473f882001-02-23 17:55:21 +0000757 else xmlMemoryDumpFile = dump;
758
759 xmlMemDisplay(xmlMemoryDumpFile);
760
761 if (dump != NULL) fclose(dump);
Daniel Veillardc064b472003-09-29 10:55:05 +0000762#endif /* MEM_LIST */
Owen Taylor3473f882001-02-23 17:55:21 +0000763}
764
765
766/****************************************************************
767 * *
768 * Initialization Routines *
769 * *
770 ****************************************************************/
771
Daniel Veillard01c13b52002-12-10 15:19:08 +0000772static int xmlInitMemoryDone = 0;
773
Owen Taylor3473f882001-02-23 17:55:21 +0000774/**
775 * xmlInitMemory:
776 *
777 * Initialize the memory layer.
778 *
779 * Returns 0 on success
780 */
Owen Taylor3473f882001-02-23 17:55:21 +0000781int
782xmlInitMemory(void)
783{
Owen Taylor3473f882001-02-23 17:55:21 +0000784#ifdef HAVE_STDLIB_H
785 char *breakpoint;
786#endif
787
William M. Brack0622fe82003-11-29 10:47:56 +0000788 xmlMemInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000789 if (xmlInitMemoryDone) return(-1);
William M. Brack0622fe82003-11-29 10:47:56 +0000790 xmlMemMutex = xmlNewMutex();
Owen Taylor3473f882001-02-23 17:55:21 +0000791
792#ifdef HAVE_STDLIB_H
793 breakpoint = getenv("XML_MEM_BREAKPOINT");
794 if (breakpoint != NULL) {
William M. Brack0622fe82003-11-29 10:47:56 +0000795 sscanf(breakpoint, "%ud", &xmlMemStopAtBlock);
Owen Taylor3473f882001-02-23 17:55:21 +0000796 }
797#endif
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000798#ifdef HAVE_STDLIB_H
799 breakpoint = getenv("XML_MEM_TRACE");
800 if (breakpoint != NULL) {
801 sscanf(breakpoint, "%p", &xmlMemTraceBlockAt);
802 }
803#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000804
805#ifdef DEBUG_MEMORY
806 xmlGenericError(xmlGenericErrorContext,
807 "xmlInitMemory() Ok\n");
808#endif
Daniel Veillardd30be4a2002-03-28 18:25:31 +0000809 xmlInitMemoryDone = 1;
810
Daniel Veillard4432df22003-09-28 18:58:27 +0000811 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +0000812}
813
814/**
815 * xmlMemSetup:
816 * @freeFunc: the free() function to use
817 * @mallocFunc: the malloc() function to use
818 * @reallocFunc: the realloc() function to use
819 * @strdupFunc: the strdup() function to use
820 *
821 * Override the default memory access functions with a new set
822 * This has to be called before any other libxml routines !
823 *
824 * Should this be blocked if there was already some allocations
825 * done ?
826 *
827 * Returns 0 on success
828 */
829int
830xmlMemSetup(xmlFreeFunc freeFunc, xmlMallocFunc mallocFunc,
831 xmlReallocFunc reallocFunc, xmlStrdupFunc strdupFunc) {
832 if (freeFunc == NULL)
833 return(-1);
834 if (mallocFunc == NULL)
835 return(-1);
836 if (reallocFunc == NULL)
837 return(-1);
838 if (strdupFunc == NULL)
839 return(-1);
840 xmlFree = freeFunc;
841 xmlMalloc = mallocFunc;
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000842 xmlMallocAtomic = mallocFunc;
Owen Taylor3473f882001-02-23 17:55:21 +0000843 xmlRealloc = reallocFunc;
844 xmlMemStrdup = strdupFunc;
845 return(0);
846}
847
848/**
849 * xmlMemGet:
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000850 * @freeFunc: place to save the free() function in use
851 * @mallocFunc: place to save the malloc() function in use
852 * @reallocFunc: place to save the realloc() function in use
853 * @strdupFunc: place to save the strdup() function in use
Owen Taylor3473f882001-02-23 17:55:21 +0000854 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000855 * Provides the memory access functions set currently in use
Owen Taylor3473f882001-02-23 17:55:21 +0000856 *
857 * Returns 0 on success
858 */
859int
860xmlMemGet(xmlFreeFunc *freeFunc, xmlMallocFunc *mallocFunc,
861 xmlReallocFunc *reallocFunc, xmlStrdupFunc *strdupFunc) {
862 if (freeFunc != NULL) *freeFunc = xmlFree;
863 if (mallocFunc != NULL) *mallocFunc = xmlMalloc;
864 if (reallocFunc != NULL) *reallocFunc = xmlRealloc;
865 if (strdupFunc != NULL) *strdupFunc = xmlMemStrdup;
866 return(0);
867}
868
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000869/**
870 * xmlGcMemSetup:
871 * @freeFunc: the free() function to use
872 * @mallocFunc: the malloc() function to use
873 * @mallocAtomicFunc: the malloc() function to use for atomic allocations
874 * @reallocFunc: the realloc() function to use
875 * @strdupFunc: the strdup() function to use
876 *
877 * Override the default memory access functions with a new set
878 * This has to be called before any other libxml routines !
879 * The mallocAtomicFunc is specialized for atomic block
880 * allocations (i.e. of areas useful for garbage collected memory allocators
881 *
882 * Should this be blocked if there was already some allocations
883 * done ?
884 *
885 * Returns 0 on success
886 */
887int
888xmlGcMemSetup(xmlFreeFunc freeFunc, xmlMallocFunc mallocFunc,
889 xmlMallocFunc mallocAtomicFunc, xmlReallocFunc reallocFunc,
890 xmlStrdupFunc strdupFunc) {
891 if (freeFunc == NULL)
892 return(-1);
893 if (mallocFunc == NULL)
894 return(-1);
895 if (mallocAtomicFunc == NULL)
896 return(-1);
897 if (reallocFunc == NULL)
898 return(-1);
899 if (strdupFunc == NULL)
900 return(-1);
901 xmlFree = freeFunc;
902 xmlMalloc = mallocFunc;
903 xmlMallocAtomic = mallocAtomicFunc;
904 xmlRealloc = reallocFunc;
905 xmlMemStrdup = strdupFunc;
906 return(0);
907}
908
909/**
910 * xmlGcMemGet:
911 * @freeFunc: place to save the free() function in use
912 * @mallocFunc: place to save the malloc() function in use
913 * @mallocAtomicFunc: place to save the atomic malloc() function in use
914 * @reallocFunc: place to save the realloc() function in use
915 * @strdupFunc: place to save the strdup() function in use
916 *
917 * Provides the memory access functions set currently in use
918 * The mallocAtomicFunc is specialized for atomic block
919 * allocations (i.e. of areas useful for garbage collected memory allocators
920 *
921 * Returns 0 on success
922 */
923int
924xmlGcMemGet(xmlFreeFunc *freeFunc, xmlMallocFunc *mallocFunc,
925 xmlMallocFunc *mallocAtomicFunc, xmlReallocFunc *reallocFunc,
926 xmlStrdupFunc *strdupFunc) {
927 if (freeFunc != NULL) *freeFunc = xmlFree;
928 if (mallocFunc != NULL) *mallocFunc = xmlMalloc;
929 if (mallocAtomicFunc != NULL) *mallocAtomicFunc = xmlMallocAtomic;
930 if (reallocFunc != NULL) *reallocFunc = xmlRealloc;
931 if (strdupFunc != NULL) *strdupFunc = xmlMemStrdup;
932 return(0);
933}
934