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