Coverage Report

Created: 2023-03-26 06:13

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