Coverage Report

Created: 2023-06-07 06:14

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