Coverage Report

Created: 2023-06-07 06:05

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