1 /*
2 * xmlmemory.c: libxml memory allocator wrapper.
3 *
4 * daniel@veillard.com
5 */
6
7 #define IN_LIBXML
8 #include "libxml.h"
9
10 #include <string.h>
11 #include <stdlib.h>
12 #include <ctype.h>
13 #include <time.h>
14
15 /* #define DEBUG_MEMORY */
16
17 /**
18 * MEM_LIST:
19 *
20 * keep track of all allocated blocks for error reporting
21 * Always build the memory list !
22 */
23 #ifdef DEBUG_MEMORY_LOCATION
24 #ifndef MEM_LIST
25 #define MEM_LIST /* keep a list of all the allocated memory blocks */
26 #endif
27 #endif
28
29 #include <libxml/globals.h> /* must come before xmlmemory.h */
30 #include <libxml/xmlmemory.h>
31 #include <libxml/xmlerror.h>
32 #include <libxml/threads.h>
33
34 static int xmlMemInitialized = 0;
35 static unsigned long debugMemSize = 0;
36 static unsigned long debugMemBlocks = 0;
37 static unsigned long debugMaxMemSize = 0;
38 static xmlMutexPtr xmlMemMutex = NULL;
39
40 void xmlMallocBreakpoint(void);
41
42 /************************************************************************
43 * *
44 * Macros, variables and associated types *
45 * *
46 ************************************************************************/
47
48 #if !defined(LIBXML_THREAD_ENABLED) && !defined(LIBXML_THREAD_ALLOC_ENABLED)
49 #ifdef xmlMalloc
50 #undef xmlMalloc
51 #endif
52 #ifdef xmlRealloc
53 #undef xmlRealloc
54 #endif
55 #ifdef xmlMemStrdup
56 #undef xmlMemStrdup
57 #endif
58 #endif
59
60 /*
61 * Each of the blocks allocated begin with a header containing information
62 */
63
64 #define MEMTAG 0x5aa5U
65
66 #define MALLOC_TYPE 1
67 #define REALLOC_TYPE 2
68 #define STRDUP_TYPE 3
69 #define MALLOC_ATOMIC_TYPE 4
70 #define REALLOC_ATOMIC_TYPE 5
71
72 typedef struct memnod {
73 unsigned int mh_tag;
74 unsigned int mh_type;
75 unsigned long mh_number;
76 size_t mh_size;
77 #ifdef MEM_LIST
78 struct memnod *mh_next;
79 struct memnod *mh_prev;
80 #endif
81 const char *mh_file;
82 unsigned int mh_line;
83 } MEMHDR;
84
85
86 #ifdef SUN4
87 #define ALIGN_SIZE 16
88 #else
89 #define ALIGN_SIZE sizeof(double)
90 #endif
91 #define HDR_SIZE sizeof(MEMHDR)
92 #define RESERVE_SIZE (((HDR_SIZE + (ALIGN_SIZE-1)) \
93 / ALIGN_SIZE ) * ALIGN_SIZE)
94
95 #define MAX_SIZE_T ((size_t)-1)
96
97 #define CLIENT_2_HDR(a) ((void *) (((char *) (a)) - RESERVE_SIZE))
98 #define HDR_2_CLIENT(a) ((void *) (((char *) (a)) + RESERVE_SIZE))
99
100
101 static unsigned int block=0;
102 static unsigned int xmlMemStopAtBlock = 0;
103 static void *xmlMemTraceBlockAt = NULL;
104 #ifdef MEM_LIST
105 static MEMHDR *memlist = NULL;
106 #endif
107
108 static void debugmem_tag_error(void *addr);
109 #ifdef MEM_LIST
110 static void debugmem_list_add(MEMHDR *);
111 static void debugmem_list_delete(MEMHDR *);
112 #endif
113 #define Mem_Tag_Err(a) debugmem_tag_error(a);
114
115 #ifndef TEST_POINT
116 #define TEST_POINT
117 #endif
118
119 /**
120 * xmlMallocBreakpoint:
121 *
122 * Breakpoint to use in conjunction with xmlMemStopAtBlock. When the block
123 * number reaches the specified value this function is called. One need to add a breakpoint
124 * to it to get the context in which the given block is allocated.
125 */
126
127 void
xmlMallocBreakpoint(void)128 xmlMallocBreakpoint(void) {
129 xmlGenericError(xmlGenericErrorContext,
130 "xmlMallocBreakpoint reached on block %d\n", xmlMemStopAtBlock);
131 }
132
133 /**
134 * xmlMallocLoc:
135 * @size: an int specifying the size in byte to allocate.
136 * @file: the file name or NULL
137 * @line: the line number
138 *
139 * a malloc() equivalent, with logging of the allocation info.
140 *
141 * Returns a pointer to the allocated area or NULL in case of lack of memory.
142 */
143
144 void *
xmlMallocLoc(size_t size,const char * file,int line)145 xmlMallocLoc(size_t size, const char * file, int line)
146 {
147 MEMHDR *p;
148 void *ret;
149
150 if (!xmlMemInitialized) xmlInitMemory();
151 #ifdef DEBUG_MEMORY
152 xmlGenericError(xmlGenericErrorContext,
153 "Malloc(%d)\n",size);
154 #endif
155
156 TEST_POINT
157
158 if (size > (MAX_SIZE_T - RESERVE_SIZE)) {
159 xmlGenericError(xmlGenericErrorContext,
160 "xmlMallocLoc : Unsigned overflow\n");
161 xmlMemoryDump();
162 return(NULL);
163 }
164
165 p = (MEMHDR *) malloc(RESERVE_SIZE+size);
166
167 if (!p) {
168 xmlGenericError(xmlGenericErrorContext,
169 "xmlMallocLoc : Out of free space\n");
170 xmlMemoryDump();
171 return(NULL);
172 }
173 p->mh_tag = MEMTAG;
174 p->mh_size = size;
175 p->mh_type = MALLOC_TYPE;
176 p->mh_file = file;
177 p->mh_line = line;
178 xmlMutexLock(xmlMemMutex);
179 p->mh_number = ++block;
180 debugMemSize += size;
181 debugMemBlocks++;
182 if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
183 #ifdef MEM_LIST
184 debugmem_list_add(p);
185 #endif
186 xmlMutexUnlock(xmlMemMutex);
187
188 #ifdef DEBUG_MEMORY
189 xmlGenericError(xmlGenericErrorContext,
190 "Malloc(%d) Ok\n",size);
191 #endif
192
193 if (xmlMemStopAtBlock == p->mh_number) xmlMallocBreakpoint();
194
195 ret = HDR_2_CLIENT(p);
196
197 if (xmlMemTraceBlockAt == ret) {
198 xmlGenericError(xmlGenericErrorContext,
199 "%p : Malloc(%lu) Ok\n", xmlMemTraceBlockAt,
200 (long unsigned)size);
201 xmlMallocBreakpoint();
202 }
203
204 TEST_POINT
205
206 return(ret);
207 }
208
209 /**
210 * xmlMallocAtomicLoc:
211 * @size: an unsigned int specifying the size in byte to allocate.
212 * @file: the file name or NULL
213 * @line: the line number
214 *
215 * a malloc() equivalent, with logging of the allocation info.
216 *
217 * Returns a pointer to the allocated area or NULL in case of lack of memory.
218 */
219
220 void *
xmlMallocAtomicLoc(size_t size,const char * file,int line)221 xmlMallocAtomicLoc(size_t size, const char * file, int line)
222 {
223 MEMHDR *p;
224 void *ret;
225
226 if (!xmlMemInitialized) xmlInitMemory();
227 #ifdef DEBUG_MEMORY
228 xmlGenericError(xmlGenericErrorContext,
229 "Malloc(%d)\n",size);
230 #endif
231
232 TEST_POINT
233
234 if (size > (MAX_SIZE_T - RESERVE_SIZE)) {
235 xmlGenericError(xmlGenericErrorContext,
236 "xmlMallocAtomicLoc : Unsigned overflow\n");
237 xmlMemoryDump();
238 return(NULL);
239 }
240
241 p = (MEMHDR *) malloc(RESERVE_SIZE+size);
242
243 if (!p) {
244 xmlGenericError(xmlGenericErrorContext,
245 "xmlMallocAtomicLoc : Out of free space\n");
246 xmlMemoryDump();
247 return(NULL);
248 }
249 p->mh_tag = MEMTAG;
250 p->mh_size = size;
251 p->mh_type = MALLOC_ATOMIC_TYPE;
252 p->mh_file = file;
253 p->mh_line = line;
254 xmlMutexLock(xmlMemMutex);
255 p->mh_number = ++block;
256 debugMemSize += size;
257 debugMemBlocks++;
258 if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
259 #ifdef MEM_LIST
260 debugmem_list_add(p);
261 #endif
262 xmlMutexUnlock(xmlMemMutex);
263
264 #ifdef DEBUG_MEMORY
265 xmlGenericError(xmlGenericErrorContext,
266 "Malloc(%d) Ok\n",size);
267 #endif
268
269 if (xmlMemStopAtBlock == p->mh_number) xmlMallocBreakpoint();
270
271 ret = HDR_2_CLIENT(p);
272
273 if (xmlMemTraceBlockAt == ret) {
274 xmlGenericError(xmlGenericErrorContext,
275 "%p : Malloc(%lu) Ok\n", xmlMemTraceBlockAt,
276 (long unsigned)size);
277 xmlMallocBreakpoint();
278 }
279
280 TEST_POINT
281
282 return(ret);
283 }
284 /**
285 * xmlMemMalloc:
286 * @size: an int specifying the size in byte to allocate.
287 *
288 * a malloc() equivalent, with logging of the allocation info.
289 *
290 * Returns a pointer to the allocated area or NULL in case of lack of memory.
291 */
292
293 void *
xmlMemMalloc(size_t size)294 xmlMemMalloc(size_t size)
295 {
296 return(xmlMallocLoc(size, "none", 0));
297 }
298
299 /**
300 * xmlReallocLoc:
301 * @ptr: the initial memory block pointer
302 * @size: an int specifying the size in byte to allocate.
303 * @file: the file name or NULL
304 * @line: the line number
305 *
306 * a realloc() equivalent, with logging of the allocation info.
307 *
308 * Returns a pointer to the allocated area or NULL in case of lack of memory.
309 */
310
311 void *
xmlReallocLoc(void * ptr,size_t size,const char * file,int line)312 xmlReallocLoc(void *ptr,size_t size, const char * file, int line)
313 {
314 MEMHDR *p, *tmp;
315 unsigned long number;
316 #ifdef DEBUG_MEMORY
317 size_t oldsize;
318 #endif
319
320 if (ptr == NULL)
321 return(xmlMallocLoc(size, file, line));
322
323 if (!xmlMemInitialized) xmlInitMemory();
324 TEST_POINT
325
326 p = CLIENT_2_HDR(ptr);
327 number = p->mh_number;
328 if (xmlMemStopAtBlock == number) xmlMallocBreakpoint();
329 if (p->mh_tag != MEMTAG) {
330 Mem_Tag_Err(p);
331 goto error;
332 }
333 p->mh_tag = ~MEMTAG;
334 xmlMutexLock(xmlMemMutex);
335 debugMemSize -= p->mh_size;
336 debugMemBlocks--;
337 #ifdef DEBUG_MEMORY
338 oldsize = p->mh_size;
339 #endif
340 #ifdef MEM_LIST
341 debugmem_list_delete(p);
342 #endif
343 xmlMutexUnlock(xmlMemMutex);
344
345 if (size > (MAX_SIZE_T - RESERVE_SIZE)) {
346 xmlGenericError(xmlGenericErrorContext,
347 "xmlReallocLoc : Unsigned overflow\n");
348 xmlMemoryDump();
349 return(NULL);
350 }
351
352 tmp = (MEMHDR *) realloc(p,RESERVE_SIZE+size);
353 if (!tmp) {
354 free(p);
355 goto error;
356 }
357 p = tmp;
358 if (xmlMemTraceBlockAt == ptr) {
359 xmlGenericError(xmlGenericErrorContext,
360 "%p : Realloced(%lu -> %lu) Ok\n",
361 xmlMemTraceBlockAt, (long unsigned)p->mh_size,
362 (long unsigned)size);
363 xmlMallocBreakpoint();
364 }
365 p->mh_tag = MEMTAG;
366 p->mh_number = number;
367 p->mh_type = REALLOC_TYPE;
368 p->mh_size = size;
369 p->mh_file = file;
370 p->mh_line = line;
371 xmlMutexLock(xmlMemMutex);
372 debugMemSize += size;
373 debugMemBlocks++;
374 if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
375 #ifdef MEM_LIST
376 debugmem_list_add(p);
377 #endif
378 xmlMutexUnlock(xmlMemMutex);
379
380 TEST_POINT
381
382 #ifdef DEBUG_MEMORY
383 xmlGenericError(xmlGenericErrorContext,
384 "Realloced(%d to %d) Ok\n", oldsize, size);
385 #endif
386 return(HDR_2_CLIENT(p));
387
388 error:
389 return(NULL);
390 }
391
392 /**
393 * xmlMemRealloc:
394 * @ptr: the initial memory block pointer
395 * @size: an int specifying the size in byte to allocate.
396 *
397 * a realloc() equivalent, with logging of the allocation info.
398 *
399 * Returns a pointer to the allocated area or NULL in case of lack of memory.
400 */
401
402 void *
xmlMemRealloc(void * ptr,size_t size)403 xmlMemRealloc(void *ptr,size_t size) {
404 return(xmlReallocLoc(ptr, size, "none", 0));
405 }
406
407 /**
408 * xmlMemFree:
409 * @ptr: the memory block pointer
410 *
411 * a free() equivalent, with error checking.
412 */
413 void
xmlMemFree(void * ptr)414 xmlMemFree(void *ptr)
415 {
416 MEMHDR *p;
417 char *target;
418 #ifdef DEBUG_MEMORY
419 size_t size;
420 #endif
421
422 if (ptr == NULL)
423 return;
424
425 if (ptr == (void *) -1) {
426 xmlGenericError(xmlGenericErrorContext,
427 "trying to free pointer from freed area\n");
428 goto error;
429 }
430
431 if (xmlMemTraceBlockAt == ptr) {
432 xmlGenericError(xmlGenericErrorContext,
433 "%p : Freed()\n", xmlMemTraceBlockAt);
434 xmlMallocBreakpoint();
435 }
436
437 TEST_POINT
438
439 target = (char *) ptr;
440
441 p = CLIENT_2_HDR(ptr);
442 if (p->mh_tag != MEMTAG) {
443 Mem_Tag_Err(p);
444 goto error;
445 }
446 if (xmlMemStopAtBlock == p->mh_number) xmlMallocBreakpoint();
447 p->mh_tag = ~MEMTAG;
448 memset(target, -1, p->mh_size);
449 xmlMutexLock(xmlMemMutex);
450 debugMemSize -= p->mh_size;
451 debugMemBlocks--;
452 #ifdef DEBUG_MEMORY
453 size = p->mh_size;
454 #endif
455 #ifdef MEM_LIST
456 debugmem_list_delete(p);
457 #endif
458 xmlMutexUnlock(xmlMemMutex);
459
460 free(p);
461
462 TEST_POINT
463
464 #ifdef DEBUG_MEMORY
465 xmlGenericError(xmlGenericErrorContext,
466 "Freed(%d) Ok\n", size);
467 #endif
468
469 return;
470
471 error:
472 xmlGenericError(xmlGenericErrorContext,
473 "xmlMemFree(%p) error\n", ptr);
474 xmlMallocBreakpoint();
475 return;
476 }
477
478 /**
479 * xmlMemStrdupLoc:
480 * @str: the initial string pointer
481 * @file: the file name or NULL
482 * @line: the line number
483 *
484 * a strdup() equivalent, with logging of the allocation info.
485 *
486 * Returns a pointer to the new string or NULL if allocation error occurred.
487 */
488
489 char *
xmlMemStrdupLoc(const char * str,const char * file,int line)490 xmlMemStrdupLoc(const char *str, const char *file, int line)
491 {
492 char *s;
493 size_t size = strlen(str) + 1;
494 MEMHDR *p;
495
496 if (!xmlMemInitialized) xmlInitMemory();
497 TEST_POINT
498
499 if (size > (MAX_SIZE_T - RESERVE_SIZE)) {
500 xmlGenericError(xmlGenericErrorContext,
501 "xmlMemStrdupLoc : Unsigned overflow\n");
502 xmlMemoryDump();
503 return(NULL);
504 }
505
506 p = (MEMHDR *) malloc(RESERVE_SIZE+size);
507 if (!p) {
508 goto error;
509 }
510 p->mh_tag = MEMTAG;
511 p->mh_size = size;
512 p->mh_type = STRDUP_TYPE;
513 p->mh_file = file;
514 p->mh_line = line;
515 xmlMutexLock(xmlMemMutex);
516 p->mh_number = ++block;
517 debugMemSize += size;
518 debugMemBlocks++;
519 if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
520 #ifdef MEM_LIST
521 debugmem_list_add(p);
522 #endif
523 xmlMutexUnlock(xmlMemMutex);
524
525 s = (char *) HDR_2_CLIENT(p);
526
527 if (xmlMemStopAtBlock == p->mh_number) xmlMallocBreakpoint();
528
529 strcpy(s,str);
530
531 TEST_POINT
532
533 if (xmlMemTraceBlockAt == s) {
534 xmlGenericError(xmlGenericErrorContext,
535 "%p : Strdup() Ok\n", xmlMemTraceBlockAt);
536 xmlMallocBreakpoint();
537 }
538
539 return(s);
540
541 error:
542 return(NULL);
543 }
544
545 /**
546 * xmlMemoryStrdup:
547 * @str: the initial string pointer
548 *
549 * a strdup() equivalent, with logging of the allocation info.
550 *
551 * Returns a pointer to the new string or NULL if allocation error occurred.
552 */
553
554 char *
xmlMemoryStrdup(const char * str)555 xmlMemoryStrdup(const char *str) {
556 return(xmlMemStrdupLoc(str, "none", 0));
557 }
558
559 /**
560 * xmlMemUsed:
561 *
562 * Provides the amount of memory currently allocated
563 *
564 * Returns an int representing the amount of memory allocated.
565 */
566
567 int
xmlMemUsed(void)568 xmlMemUsed(void) {
569 int res;
570
571 xmlMutexLock(xmlMemMutex);
572 res = debugMemSize;
573 xmlMutexUnlock(xmlMemMutex);
574 return(res);
575 }
576
577 /**
578 * xmlMemBlocks:
579 *
580 * Provides the number of memory areas currently allocated
581 *
582 * Returns an int representing the number of blocks
583 */
584
585 int
xmlMemBlocks(void)586 xmlMemBlocks(void) {
587 int res;
588
589 xmlMutexLock(xmlMemMutex);
590 res = debugMemBlocks;
591 xmlMutexUnlock(xmlMemMutex);
592 return(res);
593 }
594
595 #ifdef MEM_LIST
596 /**
597 * xmlMemContentShow:
598 * @fp: a FILE descriptor used as the output file
599 * @p: a memory block header
600 *
601 * tries to show some content from the memory block
602 */
603
604 static void
xmlMemContentShow(FILE * fp,MEMHDR * p)605 xmlMemContentShow(FILE *fp, MEMHDR *p)
606 {
607 int i,j,k,len;
608 const char *buf;
609
610 if (p == NULL) {
611 fprintf(fp, " NULL");
612 return;
613 }
614 len = p->mh_size;
615 buf = (const char *) HDR_2_CLIENT(p);
616
617 for (i = 0;i < len;i++) {
618 if (buf[i] == 0) break;
619 if (!isprint((unsigned char) buf[i])) break;
620 }
621 if ((i < 4) && ((buf[i] != 0) || (i == 0))) {
622 if (len >= 4) {
623 MEMHDR *q;
624 void *cur;
625
626 for (j = 0;(j < len -3) && (j < 40);j += 4) {
627 cur = *((void **) &buf[j]);
628 q = CLIENT_2_HDR(cur);
629 p = memlist;
630 k = 0;
631 while (p != NULL) {
632 if (p == q) break;
633 p = p->mh_next;
634 if (k++ > 100) break;
635 }
636 if ((p != NULL) && (p == q)) {
637 fprintf(fp, " pointer to #%lu at index %d",
638 p->mh_number, j);
639 return;
640 }
641 }
642 }
643 } else if ((i == 0) && (buf[i] == 0)) {
644 fprintf(fp," null");
645 } else {
646 if (buf[i] == 0) fprintf(fp," \"%.25s\"", buf);
647 else {
648 fprintf(fp," [");
649 for (j = 0;j < i;j++)
650 fprintf(fp,"%c", buf[j]);
651 fprintf(fp,"]");
652 }
653 }
654 }
655 #endif
656
657 /**
658 * xmlMemDisplayLast:
659 * @fp: a FILE descriptor used as the output file, if NULL, the result is
660 * written to the file .memorylist
661 * @nbBytes: the amount of memory to dump
662 *
663 * the last nbBytes of memory allocated and not freed, useful for dumping
664 * the memory left allocated between two places at runtime.
665 */
666
667 void
xmlMemDisplayLast(FILE * fp,long nbBytes)668 xmlMemDisplayLast(FILE *fp, long nbBytes)
669 {
670 #ifdef MEM_LIST
671 MEMHDR *p;
672 unsigned idx;
673 int nb = 0;
674 #endif
675 FILE *old_fp = fp;
676
677 if (nbBytes <= 0)
678 return;
679
680 if (fp == NULL) {
681 fp = fopen(".memorylist", "w");
682 if (fp == NULL)
683 return;
684 }
685
686 #ifdef MEM_LIST
687 fprintf(fp," Last %li MEMORY ALLOCATED : %lu, MAX was %lu\n",
688 nbBytes, debugMemSize, debugMaxMemSize);
689 fprintf(fp,"BLOCK NUMBER SIZE TYPE\n");
690 idx = 0;
691 xmlMutexLock(xmlMemMutex);
692 p = memlist;
693 while ((p) && (nbBytes > 0)) {
694 fprintf(fp,"%-5u %6lu %6lu ",idx++,p->mh_number,
695 (unsigned long)p->mh_size);
696 switch (p->mh_type) {
697 case STRDUP_TYPE:fprintf(fp,"strdup() in ");break;
698 case MALLOC_TYPE:fprintf(fp,"malloc() in ");break;
699 case REALLOC_TYPE:fprintf(fp,"realloc() in ");break;
700 case MALLOC_ATOMIC_TYPE:fprintf(fp,"atomicmalloc() in ");break;
701 case REALLOC_ATOMIC_TYPE:fprintf(fp,"atomicrealloc() in ");break;
702 default:
703 fprintf(fp,"Unknown memory block, may be corrupted");
704 xmlMutexUnlock(xmlMemMutex);
705 if (old_fp == NULL)
706 fclose(fp);
707 return;
708 }
709 if (p->mh_file != NULL) fprintf(fp,"%s(%u)", p->mh_file, p->mh_line);
710 if (p->mh_tag != MEMTAG)
711 fprintf(fp," INVALID");
712 nb++;
713 if (nb < 100)
714 xmlMemContentShow(fp, p);
715 else
716 fprintf(fp," skip");
717
718 fprintf(fp,"\n");
719 nbBytes -= (unsigned long)p->mh_size;
720 p = p->mh_next;
721 }
722 xmlMutexUnlock(xmlMemMutex);
723 #else
724 fprintf(fp,"Memory list not compiled (MEM_LIST not defined !)\n");
725 #endif
726 if (old_fp == NULL)
727 fclose(fp);
728 }
729
730 /**
731 * xmlMemDisplay:
732 * @fp: a FILE descriptor used as the output file, if NULL, the result is
733 * written to the file .memorylist
734 *
735 * show in-extenso the memory blocks allocated
736 */
737
738 void
xmlMemDisplay(FILE * fp)739 xmlMemDisplay(FILE *fp)
740 {
741 #ifdef MEM_LIST
742 MEMHDR *p;
743 unsigned idx;
744 int nb = 0;
745 time_t currentTime;
746 char buf[500];
747 struct tm * tstruct;
748 #endif
749 FILE *old_fp = fp;
750
751 if (fp == NULL) {
752 fp = fopen(".memorylist", "w");
753 if (fp == NULL)
754 return;
755 }
756
757 #ifdef MEM_LIST
758 currentTime = time(NULL);
759 tstruct = localtime(¤tTime);
760 strftime(buf, sizeof(buf) - 1, "%I:%M:%S %p", tstruct);
761 fprintf(fp," %s\n\n", buf);
762
763
764 fprintf(fp," MEMORY ALLOCATED : %lu, MAX was %lu\n",
765 debugMemSize, debugMaxMemSize);
766 fprintf(fp,"BLOCK NUMBER SIZE TYPE\n");
767 idx = 0;
768 xmlMutexLock(xmlMemMutex);
769 p = memlist;
770 while (p) {
771 fprintf(fp,"%-5u %6lu %6lu ",idx++,p->mh_number,
772 (unsigned long)p->mh_size);
773 switch (p->mh_type) {
774 case STRDUP_TYPE:fprintf(fp,"strdup() in ");break;
775 case MALLOC_TYPE:fprintf(fp,"malloc() in ");break;
776 case REALLOC_TYPE:fprintf(fp,"realloc() in ");break;
777 case MALLOC_ATOMIC_TYPE:fprintf(fp,"atomicmalloc() in ");break;
778 case REALLOC_ATOMIC_TYPE:fprintf(fp,"atomicrealloc() in ");break;
779 default:
780 fprintf(fp,"Unknown memory block, may be corrupted");
781 xmlMutexUnlock(xmlMemMutex);
782 if (old_fp == NULL)
783 fclose(fp);
784 return;
785 }
786 if (p->mh_file != NULL) fprintf(fp,"%s(%u)", p->mh_file, p->mh_line);
787 if (p->mh_tag != MEMTAG)
788 fprintf(fp," INVALID");
789 nb++;
790 if (nb < 100)
791 xmlMemContentShow(fp, p);
792 else
793 fprintf(fp," skip");
794
795 fprintf(fp,"\n");
796 p = p->mh_next;
797 }
798 xmlMutexUnlock(xmlMemMutex);
799 #else
800 fprintf(fp,"Memory list not compiled (MEM_LIST not defined !)\n");
801 #endif
802 if (old_fp == NULL)
803 fclose(fp);
804 }
805
806 #ifdef MEM_LIST
807
debugmem_list_add(MEMHDR * p)808 static void debugmem_list_add(MEMHDR *p)
809 {
810 p->mh_next = memlist;
811 p->mh_prev = NULL;
812 if (memlist) memlist->mh_prev = p;
813 memlist = p;
814 #ifdef MEM_LIST_DEBUG
815 if (stderr)
816 Mem_Display(stderr);
817 #endif
818 }
819
debugmem_list_delete(MEMHDR * p)820 static void debugmem_list_delete(MEMHDR *p)
821 {
822 if (p->mh_next)
823 p->mh_next->mh_prev = p->mh_prev;
824 if (p->mh_prev)
825 p->mh_prev->mh_next = p->mh_next;
826 else memlist = p->mh_next;
827 #ifdef MEM_LIST_DEBUG
828 if (stderr)
829 Mem_Display(stderr);
830 #endif
831 }
832
833 #endif
834
835 /*
836 * debugmem_tag_error:
837 *
838 * internal error function.
839 */
840
debugmem_tag_error(void * p)841 static void debugmem_tag_error(void *p)
842 {
843 xmlGenericError(xmlGenericErrorContext,
844 "Memory tag error occurs :%p \n\t bye\n", p);
845 #ifdef MEM_LIST
846 if (stderr)
847 xmlMemDisplay(stderr);
848 #endif
849 }
850
851 #ifdef MEM_LIST
852 static FILE *xmlMemoryDumpFile = NULL;
853 #endif
854
855 /**
856 * xmlMemShow:
857 * @fp: a FILE descriptor used as the output file
858 * @nr: number of entries to dump
859 *
860 * show a show display of the memory allocated, and dump
861 * the @nr last allocated areas which were not freed
862 */
863
864 void
xmlMemShow(FILE * fp,int nr ATTRIBUTE_UNUSED)865 xmlMemShow(FILE *fp, int nr ATTRIBUTE_UNUSED)
866 {
867 #ifdef MEM_LIST
868 MEMHDR *p;
869 #endif
870
871 if (fp != NULL)
872 fprintf(fp," MEMORY ALLOCATED : %lu, MAX was %lu\n",
873 debugMemSize, debugMaxMemSize);
874 #ifdef MEM_LIST
875 xmlMutexLock(xmlMemMutex);
876 if (nr > 0) {
877 fprintf(fp,"NUMBER SIZE TYPE WHERE\n");
878 p = memlist;
879 while ((p) && nr > 0) {
880 fprintf(fp,"%6lu %6lu ",p->mh_number,(unsigned long)p->mh_size);
881 switch (p->mh_type) {
882 case STRDUP_TYPE:fprintf(fp,"strdup() in ");break;
883 case MALLOC_TYPE:fprintf(fp,"malloc() in ");break;
884 case MALLOC_ATOMIC_TYPE:fprintf(fp,"atomicmalloc() in ");break;
885 case REALLOC_TYPE:fprintf(fp,"realloc() in ");break;
886 case REALLOC_ATOMIC_TYPE:fprintf(fp,"atomicrealloc() in ");break;
887 default:fprintf(fp," ??? in ");break;
888 }
889 if (p->mh_file != NULL)
890 fprintf(fp,"%s(%u)", p->mh_file, p->mh_line);
891 if (p->mh_tag != MEMTAG)
892 fprintf(fp," INVALID");
893 xmlMemContentShow(fp, p);
894 fprintf(fp,"\n");
895 nr--;
896 p = p->mh_next;
897 }
898 }
899 xmlMutexUnlock(xmlMemMutex);
900 #endif /* MEM_LIST */
901 }
902
903 /**
904 * xmlMemoryDump:
905 *
906 * Dump in-extenso the memory blocks allocated to the file .memorylist
907 */
908
909 void
xmlMemoryDump(void)910 xmlMemoryDump(void)
911 {
912 #ifdef MEM_LIST
913 FILE *dump;
914
915 if (debugMaxMemSize == 0)
916 return;
917 dump = fopen(".memdump", "w");
918 if (dump == NULL)
919 xmlMemoryDumpFile = stderr;
920 else xmlMemoryDumpFile = dump;
921
922 xmlMemDisplay(xmlMemoryDumpFile);
923
924 if (dump != NULL) fclose(dump);
925 #endif /* MEM_LIST */
926 }
927
928
929 /****************************************************************
930 * *
931 * Initialization Routines *
932 * *
933 ****************************************************************/
934
935 /**
936 * xmlInitMemory:
937 *
938 * DEPRECATED: This function will be made private. Call xmlInitParser to
939 * initialize the library.
940 *
941 * Initialize the memory layer.
942 *
943 * Returns 0 on success
944 */
945 int
xmlInitMemory(void)946 xmlInitMemory(void)
947 {
948 char *breakpoint;
949 #ifdef DEBUG_MEMORY
950 xmlGenericError(xmlGenericErrorContext,
951 "xmlInitMemory()\n");
952 #endif
953 /*
954 This is really not good code (see Bug 130419). Suggestions for
955 improvement will be welcome!
956 */
957 if (xmlMemInitialized) return(-1);
958 xmlMemInitialized = 1;
959 xmlMemMutex = xmlNewMutex();
960
961 breakpoint = getenv("XML_MEM_BREAKPOINT");
962 if (breakpoint != NULL) {
963 sscanf(breakpoint, "%ud", &xmlMemStopAtBlock);
964 }
965 breakpoint = getenv("XML_MEM_TRACE");
966 if (breakpoint != NULL) {
967 sscanf(breakpoint, "%p", &xmlMemTraceBlockAt);
968 }
969
970 #ifdef DEBUG_MEMORY
971 xmlGenericError(xmlGenericErrorContext,
972 "xmlInitMemory() Ok\n");
973 #endif
974 return(0);
975 }
976
977 /**
978 * xmlCleanupMemory:
979 *
980 * DEPRECATED: This function will be made private. Call xmlCleanupParser
981 * to free global state but see the warnings there. xmlCleanupParser
982 * should be only called once at program exit. In most cases, you don't
983 * have call cleanup functions at all.
984 *
985 * Free up all the memory allocated by the library for its own
986 * use. This should not be called by user level code.
987 */
988 void
xmlCleanupMemory(void)989 xmlCleanupMemory(void) {
990 #ifdef DEBUG_MEMORY
991 xmlGenericError(xmlGenericErrorContext,
992 "xmlCleanupMemory()\n");
993 #endif
994 if (xmlMemInitialized == 0)
995 return;
996
997 xmlFreeMutex(xmlMemMutex);
998 xmlMemMutex = NULL;
999 xmlMemInitialized = 0;
1000 #ifdef DEBUG_MEMORY
1001 xmlGenericError(xmlGenericErrorContext,
1002 "xmlCleanupMemory() Ok\n");
1003 #endif
1004 }
1005
1006 /**
1007 * xmlMemSetup:
1008 * @freeFunc: the free() function to use
1009 * @mallocFunc: the malloc() function to use
1010 * @reallocFunc: the realloc() function to use
1011 * @strdupFunc: the strdup() function to use
1012 *
1013 * Override the default memory access functions with a new set
1014 * This has to be called before any other libxml routines !
1015 *
1016 * Should this be blocked if there was already some allocations
1017 * done ?
1018 *
1019 * Returns 0 on success
1020 */
1021 int
xmlMemSetup(xmlFreeFunc freeFunc,xmlMallocFunc mallocFunc,xmlReallocFunc reallocFunc,xmlStrdupFunc strdupFunc)1022 xmlMemSetup(xmlFreeFunc freeFunc, xmlMallocFunc mallocFunc,
1023 xmlReallocFunc reallocFunc, xmlStrdupFunc strdupFunc) {
1024 #ifdef DEBUG_MEMORY
1025 xmlGenericError(xmlGenericErrorContext,
1026 "xmlMemSetup()\n");
1027 #endif
1028 if (freeFunc == NULL)
1029 return(-1);
1030 if (mallocFunc == NULL)
1031 return(-1);
1032 if (reallocFunc == NULL)
1033 return(-1);
1034 if (strdupFunc == NULL)
1035 return(-1);
1036 xmlFree = freeFunc;
1037 xmlMalloc = mallocFunc;
1038 xmlMallocAtomic = mallocFunc;
1039 xmlRealloc = reallocFunc;
1040 xmlMemStrdup = strdupFunc;
1041 #ifdef DEBUG_MEMORY
1042 xmlGenericError(xmlGenericErrorContext,
1043 "xmlMemSetup() Ok\n");
1044 #endif
1045 return(0);
1046 }
1047
1048 /**
1049 * xmlMemGet:
1050 * @freeFunc: place to save the free() function in use
1051 * @mallocFunc: place to save the malloc() function in use
1052 * @reallocFunc: place to save the realloc() function in use
1053 * @strdupFunc: place to save the strdup() function in use
1054 *
1055 * Provides the memory access functions set currently in use
1056 *
1057 * Returns 0 on success
1058 */
1059 int
xmlMemGet(xmlFreeFunc * freeFunc,xmlMallocFunc * mallocFunc,xmlReallocFunc * reallocFunc,xmlStrdupFunc * strdupFunc)1060 xmlMemGet(xmlFreeFunc *freeFunc, xmlMallocFunc *mallocFunc,
1061 xmlReallocFunc *reallocFunc, xmlStrdupFunc *strdupFunc) {
1062 if (freeFunc != NULL) *freeFunc = xmlFree;
1063 if (mallocFunc != NULL) *mallocFunc = xmlMalloc;
1064 if (reallocFunc != NULL) *reallocFunc = xmlRealloc;
1065 if (strdupFunc != NULL) *strdupFunc = xmlMemStrdup;
1066 return(0);
1067 }
1068
1069 /**
1070 * xmlGcMemSetup:
1071 * @freeFunc: the free() function to use
1072 * @mallocFunc: the malloc() function to use
1073 * @mallocAtomicFunc: the malloc() function to use for atomic allocations
1074 * @reallocFunc: the realloc() function to use
1075 * @strdupFunc: the strdup() function to use
1076 *
1077 * Override the default memory access functions with a new set
1078 * This has to be called before any other libxml routines !
1079 * The mallocAtomicFunc is specialized for atomic block
1080 * allocations (i.e. of areas useful for garbage collected memory allocators
1081 *
1082 * Should this be blocked if there was already some allocations
1083 * done ?
1084 *
1085 * Returns 0 on success
1086 */
1087 int
xmlGcMemSetup(xmlFreeFunc freeFunc,xmlMallocFunc mallocFunc,xmlMallocFunc mallocAtomicFunc,xmlReallocFunc reallocFunc,xmlStrdupFunc strdupFunc)1088 xmlGcMemSetup(xmlFreeFunc freeFunc, xmlMallocFunc mallocFunc,
1089 xmlMallocFunc mallocAtomicFunc, xmlReallocFunc reallocFunc,
1090 xmlStrdupFunc strdupFunc) {
1091 #ifdef DEBUG_MEMORY
1092 xmlGenericError(xmlGenericErrorContext,
1093 "xmlGcMemSetup()\n");
1094 #endif
1095 if (freeFunc == NULL)
1096 return(-1);
1097 if (mallocFunc == NULL)
1098 return(-1);
1099 if (mallocAtomicFunc == NULL)
1100 return(-1);
1101 if (reallocFunc == NULL)
1102 return(-1);
1103 if (strdupFunc == NULL)
1104 return(-1);
1105 xmlFree = freeFunc;
1106 xmlMalloc = mallocFunc;
1107 xmlMallocAtomic = mallocAtomicFunc;
1108 xmlRealloc = reallocFunc;
1109 xmlMemStrdup = strdupFunc;
1110 #ifdef DEBUG_MEMORY
1111 xmlGenericError(xmlGenericErrorContext,
1112 "xmlGcMemSetup() Ok\n");
1113 #endif
1114 return(0);
1115 }
1116
1117 /**
1118 * xmlGcMemGet:
1119 * @freeFunc: place to save the free() function in use
1120 * @mallocFunc: place to save the malloc() function in use
1121 * @mallocAtomicFunc: place to save the atomic malloc() function in use
1122 * @reallocFunc: place to save the realloc() function in use
1123 * @strdupFunc: place to save the strdup() function in use
1124 *
1125 * Provides the memory access functions set currently in use
1126 * The mallocAtomicFunc is specialized for atomic block
1127 * allocations (i.e. of areas useful for garbage collected memory allocators
1128 *
1129 * Returns 0 on success
1130 */
1131 int
xmlGcMemGet(xmlFreeFunc * freeFunc,xmlMallocFunc * mallocFunc,xmlMallocFunc * mallocAtomicFunc,xmlReallocFunc * reallocFunc,xmlStrdupFunc * strdupFunc)1132 xmlGcMemGet(xmlFreeFunc *freeFunc, xmlMallocFunc *mallocFunc,
1133 xmlMallocFunc *mallocAtomicFunc, xmlReallocFunc *reallocFunc,
1134 xmlStrdupFunc *strdupFunc) {
1135 if (freeFunc != NULL) *freeFunc = xmlFree;
1136 if (mallocFunc != NULL) *mallocFunc = xmlMalloc;
1137 if (mallocAtomicFunc != NULL) *mallocAtomicFunc = xmlMallocAtomic;
1138 if (reallocFunc != NULL) *reallocFunc = xmlRealloc;
1139 if (strdupFunc != NULL) *strdupFunc = xmlMemStrdup;
1140 return(0);
1141 }
1142
1143