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