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 * xmlMemUsed:
563 *
564 * Provides the amount of memory currently allocated
565 *
566 * Returns an int representing the amount of memory allocated.
567 */
568
569 int
xmlMemUsed(void)570 xmlMemUsed(void) {
571 return(debugMemSize);
572 }
573
574 /**
575 * xmlMemBlocks:
576 *
577 * Provides the number of memory areas currently allocated
578 *
579 * Returns an int representing the number of blocks
580 */
581
582 int
xmlMemBlocks(void)583 xmlMemBlocks(void) {
584 int res;
585
586 xmlMutexLock(&xmlMemMutex);
587 res = debugMemBlocks;
588 xmlMutexUnlock(&xmlMemMutex);
589 return(res);
590 }
591
592 /**
593 * xmlMemDisplayLast:
594 * @fp: a FILE descriptor used as the output file, if NULL, the result is
595 * written to the file .memorylist
596 * @nbBytes: the amount of memory to dump
597 *
598 * the last nbBytes of memory allocated and not freed, useful for dumping
599 * the memory left allocated between two places at runtime.
600 */
601
602 void
xmlMemDisplayLast(FILE * fp,long nbBytes)603 xmlMemDisplayLast(FILE *fp, long nbBytes)
604 {
605 #ifdef MEM_LIST
606 MEMHDR *p;
607 unsigned idx;
608 int nb = 0;
609 #endif
610 FILE *old_fp = fp;
611
612 if (nbBytes <= 0)
613 return;
614
615 if (fp == NULL) {
616 fp = fopen(".memorylist", "w");
617 if (fp == NULL)
618 return;
619 }
620
621 #ifdef MEM_LIST
622 fprintf(fp," Last %li MEMORY ALLOCATED : %lu, MAX was %lu\n",
623 nbBytes, debugMemSize, debugMaxMemSize);
624 fprintf(fp,"BLOCK NUMBER SIZE TYPE\n");
625 idx = 0;
626 xmlMutexLock(&xmlMemMutex);
627 p = memlist;
628 while ((p) && (nbBytes > 0)) {
629 fprintf(fp,"%-5u %6lu %6lu ",idx++,p->mh_number,
630 (unsigned long)p->mh_size);
631 switch (p->mh_type) {
632 case STRDUP_TYPE:fprintf(fp,"strdup() in ");break;
633 case MALLOC_TYPE:fprintf(fp,"malloc() in ");break;
634 case REALLOC_TYPE:fprintf(fp,"realloc() in ");break;
635 case MALLOC_ATOMIC_TYPE:fprintf(fp,"atomicmalloc() in ");break;
636 case REALLOC_ATOMIC_TYPE:fprintf(fp,"atomicrealloc() in ");break;
637 default:
638 fprintf(fp,"Unknown memory block, may be corrupted");
639 xmlMutexUnlock(&xmlMemMutex);
640 if (old_fp == NULL)
641 fclose(fp);
642 return;
643 }
644 if (p->mh_file != NULL) fprintf(fp,"%s(%u)", p->mh_file, p->mh_line);
645 if (p->mh_tag != MEMTAG)
646 fprintf(fp," INVALID");
647 nb++;
648
649 fprintf(fp,"\n");
650 nbBytes -= (unsigned long)p->mh_size;
651 p = p->mh_next;
652 }
653 xmlMutexUnlock(&xmlMemMutex);
654 #else
655 fprintf(fp,"Memory list not compiled (MEM_LIST not defined !)\n");
656 #endif
657 if (old_fp == NULL)
658 fclose(fp);
659 }
660
661 /**
662 * xmlMemDisplay:
663 * @fp: a FILE descriptor used as the output file, if NULL, the result is
664 * written to the file .memorylist
665 *
666 * show in-extenso the memory blocks allocated
667 */
668
669 void
xmlMemDisplay(FILE * fp)670 xmlMemDisplay(FILE *fp)
671 {
672 #ifdef MEM_LIST
673 MEMHDR *p;
674 unsigned idx;
675 int nb = 0;
676 time_t currentTime;
677 char buf[500];
678 struct tm * tstruct;
679 #endif
680 FILE *old_fp = fp;
681
682 if (fp == NULL) {
683 fp = fopen(".memorylist", "w");
684 if (fp == NULL)
685 return;
686 }
687
688 #ifdef MEM_LIST
689 currentTime = time(NULL);
690 tstruct = localtime(¤tTime);
691 strftime(buf, sizeof(buf) - 1, "%I:%M:%S %p", tstruct);
692 fprintf(fp," %s\n\n", buf);
693
694
695 fprintf(fp," MEMORY ALLOCATED : %lu, MAX was %lu\n",
696 debugMemSize, debugMaxMemSize);
697 fprintf(fp,"BLOCK NUMBER SIZE TYPE\n");
698 idx = 0;
699 xmlMutexLock(&xmlMemMutex);
700 p = memlist;
701 while (p) {
702 fprintf(fp,"%-5u %6lu %6lu ",idx++,p->mh_number,
703 (unsigned long)p->mh_size);
704 switch (p->mh_type) {
705 case STRDUP_TYPE:fprintf(fp,"strdup() in ");break;
706 case MALLOC_TYPE:fprintf(fp,"malloc() in ");break;
707 case REALLOC_TYPE:fprintf(fp,"realloc() in ");break;
708 case MALLOC_ATOMIC_TYPE:fprintf(fp,"atomicmalloc() in ");break;
709 case REALLOC_ATOMIC_TYPE:fprintf(fp,"atomicrealloc() in ");break;
710 default:
711 fprintf(fp,"Unknown memory block, may be corrupted");
712 xmlMutexUnlock(&xmlMemMutex);
713 if (old_fp == NULL)
714 fclose(fp);
715 return;
716 }
717 if (p->mh_file != NULL) fprintf(fp,"%s(%u)", p->mh_file, p->mh_line);
718 if (p->mh_tag != MEMTAG)
719 fprintf(fp," INVALID");
720 nb++;
721
722 fprintf(fp,"\n");
723 p = p->mh_next;
724 }
725 xmlMutexUnlock(&xmlMemMutex);
726 #else
727 fprintf(fp,"Memory list not compiled (MEM_LIST not defined !)\n");
728 #endif
729 if (old_fp == NULL)
730 fclose(fp);
731 }
732
733 #ifdef MEM_LIST
734
debugmem_list_add(MEMHDR * p)735 static void debugmem_list_add(MEMHDR *p)
736 {
737 p->mh_next = memlist;
738 p->mh_prev = NULL;
739 if (memlist) memlist->mh_prev = p;
740 memlist = p;
741 #ifdef MEM_LIST_DEBUG
742 if (stderr)
743 Mem_Display(stderr);
744 #endif
745 }
746
debugmem_list_delete(MEMHDR * p)747 static void debugmem_list_delete(MEMHDR *p)
748 {
749 if (p->mh_next)
750 p->mh_next->mh_prev = p->mh_prev;
751 if (p->mh_prev)
752 p->mh_prev->mh_next = p->mh_next;
753 else memlist = p->mh_next;
754 #ifdef MEM_LIST_DEBUG
755 if (stderr)
756 Mem_Display(stderr);
757 #endif
758 }
759
760 #endif
761
762 /*
763 * debugmem_tag_error:
764 *
765 * internal error function.
766 */
767
debugmem_tag_error(void * p)768 static void debugmem_tag_error(void *p)
769 {
770 xmlGenericError(xmlGenericErrorContext,
771 "Memory tag error occurs :%p \n\t bye\n", p);
772 #ifdef MEM_LIST
773 if (stderr)
774 xmlMemDisplay(stderr);
775 #endif
776 }
777
778 #ifdef MEM_LIST
779 static FILE *xmlMemoryDumpFile = NULL;
780 #endif
781
782 /**
783 * xmlMemShow:
784 * @fp: a FILE descriptor used as the output file
785 * @nr: number of entries to dump
786 *
787 * show a show display of the memory allocated, and dump
788 * the @nr last allocated areas which were not freed
789 */
790
791 void
xmlMemShow(FILE * fp,int nr ATTRIBUTE_UNUSED)792 xmlMemShow(FILE *fp, int nr ATTRIBUTE_UNUSED)
793 {
794 #ifdef MEM_LIST
795 MEMHDR *p;
796 #endif
797
798 if (fp != NULL)
799 fprintf(fp," MEMORY ALLOCATED : %lu, MAX was %lu\n",
800 debugMemSize, debugMaxMemSize);
801 #ifdef MEM_LIST
802 xmlMutexLock(&xmlMemMutex);
803 if (nr > 0) {
804 fprintf(fp,"NUMBER SIZE TYPE WHERE\n");
805 p = memlist;
806 while ((p) && nr > 0) {
807 fprintf(fp,"%6lu %6lu ",p->mh_number,(unsigned long)p->mh_size);
808 switch (p->mh_type) {
809 case STRDUP_TYPE:fprintf(fp,"strdup() in ");break;
810 case MALLOC_TYPE:fprintf(fp,"malloc() in ");break;
811 case MALLOC_ATOMIC_TYPE:fprintf(fp,"atomicmalloc() in ");break;
812 case REALLOC_TYPE:fprintf(fp,"realloc() in ");break;
813 case REALLOC_ATOMIC_TYPE:fprintf(fp,"atomicrealloc() in ");break;
814 default:fprintf(fp," ??? in ");break;
815 }
816 if (p->mh_file != NULL)
817 fprintf(fp,"%s(%u)", p->mh_file, p->mh_line);
818 if (p->mh_tag != MEMTAG)
819 fprintf(fp," INVALID");
820 fprintf(fp,"\n");
821 nr--;
822 p = p->mh_next;
823 }
824 }
825 xmlMutexUnlock(&xmlMemMutex);
826 #endif /* MEM_LIST */
827 }
828
829 /**
830 * xmlMemoryDump:
831 *
832 * Dump in-extenso the memory blocks allocated to the file .memorylist
833 */
834
835 void
xmlMemoryDump(void)836 xmlMemoryDump(void)
837 {
838 #ifdef MEM_LIST
839 FILE *dump;
840
841 if (debugMaxMemSize == 0)
842 return;
843 dump = fopen(".memdump", "w");
844 if (dump == NULL)
845 xmlMemoryDumpFile = stderr;
846 else xmlMemoryDumpFile = dump;
847
848 xmlMemDisplay(xmlMemoryDumpFile);
849
850 if (dump != NULL) fclose(dump);
851 #endif /* MEM_LIST */
852 }
853
854
855 /****************************************************************
856 * *
857 * Initialization Routines *
858 * *
859 ****************************************************************/
860
861 /**
862 * xmlInitMemory:
863 *
864 * DEPRECATED: Alias for xmlInitParser.
865 */
866 int
xmlInitMemory(void)867 xmlInitMemory(void) {
868 xmlInitParser();
869 return(0);
870 }
871
872 /**
873 * xmlInitMemoryInternal:
874 *
875 * Initialize the memory layer.
876 *
877 * Returns 0 on success
878 */
879 void
xmlInitMemoryInternal(void)880 xmlInitMemoryInternal(void) {
881 char *breakpoint;
882 #ifdef DEBUG_MEMORY
883 xmlGenericError(xmlGenericErrorContext,
884 "xmlInitMemory()\n");
885 #endif
886 xmlInitMutex(&xmlMemMutex);
887
888 breakpoint = getenv("XML_MEM_BREAKPOINT");
889 if (breakpoint != NULL) {
890 sscanf(breakpoint, "%ud", &xmlMemStopAtBlock);
891 }
892 breakpoint = getenv("XML_MEM_TRACE");
893 if (breakpoint != NULL) {
894 sscanf(breakpoint, "%p", &xmlMemTraceBlockAt);
895 }
896
897 #ifdef DEBUG_MEMORY
898 xmlGenericError(xmlGenericErrorContext,
899 "xmlInitMemory() Ok\n");
900 #endif
901 }
902
903 /**
904 * xmlCleanupMemory:
905 *
906 * DEPRECATED: This function is a no-op. Call xmlCleanupParser
907 * to free global state but see the warnings there. xmlCleanupParser
908 * should be only called once at program exit. In most cases, you don't
909 * have call cleanup functions at all.
910 */
911 void
xmlCleanupMemory(void)912 xmlCleanupMemory(void) {
913 }
914
915 /**
916 * xmlCleanupMemoryInternal:
917 *
918 * Free up all the memory allocated by the library for its own
919 * use. This should not be called by user level code.
920 */
921 void
xmlCleanupMemoryInternal(void)922 xmlCleanupMemoryInternal(void) {
923 #ifdef DEBUG_MEMORY
924 xmlGenericError(xmlGenericErrorContext,
925 "xmlCleanupMemory()\n");
926 #endif
927
928 xmlCleanupMutex(&xmlMemMutex);
929 #ifdef DEBUG_MEMORY
930 xmlGenericError(xmlGenericErrorContext,
931 "xmlCleanupMemory() Ok\n");
932 #endif
933 }
934
935 /**
936 * xmlMemSetup:
937 * @freeFunc: the free() function to use
938 * @mallocFunc: the malloc() function to use
939 * @reallocFunc: the realloc() function to use
940 * @strdupFunc: the strdup() function to use
941 *
942 * Override the default memory access functions with a new set
943 * This has to be called before any other libxml routines !
944 *
945 * Should this be blocked if there was already some allocations
946 * done ?
947 *
948 * Returns 0 on success
949 */
950 int
xmlMemSetup(xmlFreeFunc freeFunc,xmlMallocFunc mallocFunc,xmlReallocFunc reallocFunc,xmlStrdupFunc strdupFunc)951 xmlMemSetup(xmlFreeFunc freeFunc, xmlMallocFunc mallocFunc,
952 xmlReallocFunc reallocFunc, xmlStrdupFunc strdupFunc) {
953 #ifdef DEBUG_MEMORY
954 xmlGenericError(xmlGenericErrorContext,
955 "xmlMemSetup()\n");
956 #endif
957 if (freeFunc == NULL)
958 return(-1);
959 if (mallocFunc == NULL)
960 return(-1);
961 if (reallocFunc == NULL)
962 return(-1);
963 if (strdupFunc == NULL)
964 return(-1);
965 xmlFree = freeFunc;
966 xmlMalloc = mallocFunc;
967 xmlMallocAtomic = mallocFunc;
968 xmlRealloc = reallocFunc;
969 xmlMemStrdup = strdupFunc;
970 #ifdef DEBUG_MEMORY
971 xmlGenericError(xmlGenericErrorContext,
972 "xmlMemSetup() Ok\n");
973 #endif
974 return(0);
975 }
976
977 /**
978 * xmlMemGet:
979 * @freeFunc: place to save the free() function in use
980 * @mallocFunc: place to save the malloc() function in use
981 * @reallocFunc: place to save the realloc() function in use
982 * @strdupFunc: place to save the strdup() function in use
983 *
984 * Provides the memory access functions set currently in use
985 *
986 * Returns 0 on success
987 */
988 int
xmlMemGet(xmlFreeFunc * freeFunc,xmlMallocFunc * mallocFunc,xmlReallocFunc * reallocFunc,xmlStrdupFunc * strdupFunc)989 xmlMemGet(xmlFreeFunc *freeFunc, xmlMallocFunc *mallocFunc,
990 xmlReallocFunc *reallocFunc, xmlStrdupFunc *strdupFunc) {
991 if (freeFunc != NULL) *freeFunc = xmlFree;
992 if (mallocFunc != NULL) *mallocFunc = xmlMalloc;
993 if (reallocFunc != NULL) *reallocFunc = xmlRealloc;
994 if (strdupFunc != NULL) *strdupFunc = xmlMemStrdup;
995 return(0);
996 }
997
998 /**
999 * xmlGcMemSetup:
1000 * @freeFunc: the free() function to use
1001 * @mallocFunc: the malloc() function to use
1002 * @mallocAtomicFunc: the malloc() function to use for atomic allocations
1003 * @reallocFunc: the realloc() function to use
1004 * @strdupFunc: the strdup() function to use
1005 *
1006 * Override the default memory access functions with a new set
1007 * This has to be called before any other libxml routines !
1008 * The mallocAtomicFunc is specialized for atomic block
1009 * allocations (i.e. of areas useful for garbage collected memory allocators
1010 *
1011 * Should this be blocked if there was already some allocations
1012 * done ?
1013 *
1014 * Returns 0 on success
1015 */
1016 int
xmlGcMemSetup(xmlFreeFunc freeFunc,xmlMallocFunc mallocFunc,xmlMallocFunc mallocAtomicFunc,xmlReallocFunc reallocFunc,xmlStrdupFunc strdupFunc)1017 xmlGcMemSetup(xmlFreeFunc freeFunc, xmlMallocFunc mallocFunc,
1018 xmlMallocFunc mallocAtomicFunc, xmlReallocFunc reallocFunc,
1019 xmlStrdupFunc strdupFunc) {
1020 #ifdef DEBUG_MEMORY
1021 xmlGenericError(xmlGenericErrorContext,
1022 "xmlGcMemSetup()\n");
1023 #endif
1024 if (freeFunc == NULL)
1025 return(-1);
1026 if (mallocFunc == NULL)
1027 return(-1);
1028 if (mallocAtomicFunc == NULL)
1029 return(-1);
1030 if (reallocFunc == NULL)
1031 return(-1);
1032 if (strdupFunc == NULL)
1033 return(-1);
1034 xmlFree = freeFunc;
1035 xmlMalloc = mallocFunc;
1036 xmlMallocAtomic = mallocAtomicFunc;
1037 xmlRealloc = reallocFunc;
1038 xmlMemStrdup = strdupFunc;
1039 #ifdef DEBUG_MEMORY
1040 xmlGenericError(xmlGenericErrorContext,
1041 "xmlGcMemSetup() Ok\n");
1042 #endif
1043 return(0);
1044 }
1045
1046 /**
1047 * xmlGcMemGet:
1048 * @freeFunc: place to save the free() function in use
1049 * @mallocFunc: place to save the malloc() function in use
1050 * @mallocAtomicFunc: place to save the atomic malloc() function in use
1051 * @reallocFunc: place to save the realloc() function in use
1052 * @strdupFunc: place to save the strdup() function in use
1053 *
1054 * Provides the memory access functions set currently in use
1055 * The mallocAtomicFunc is specialized for atomic block
1056 * allocations (i.e. of areas useful for garbage collected memory allocators
1057 *
1058 * Returns 0 on success
1059 */
1060 int
xmlGcMemGet(xmlFreeFunc * freeFunc,xmlMallocFunc * mallocFunc,xmlMallocFunc * mallocAtomicFunc,xmlReallocFunc * reallocFunc,xmlStrdupFunc * strdupFunc)1061 xmlGcMemGet(xmlFreeFunc *freeFunc, xmlMallocFunc *mallocFunc,
1062 xmlMallocFunc *mallocAtomicFunc, xmlReallocFunc *reallocFunc,
1063 xmlStrdupFunc *strdupFunc) {
1064 if (freeFunc != NULL) *freeFunc = xmlFree;
1065 if (mallocFunc != NULL) *mallocFunc = xmlMalloc;
1066 if (mallocAtomicFunc != NULL) *mallocAtomicFunc = xmlMallocAtomic;
1067 if (reallocFunc != NULL) *reallocFunc = xmlRealloc;
1068 if (strdupFunc != NULL) *strdupFunc = xmlMemStrdup;
1069 return(0);
1070 }
1071
1072