Coverage Report

Created: 2025-08-04 07:15

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