Coverage Report

Created: 2024-09-06 07:53

/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
#include <libxml/xmlmemory.h>
16
#include <libxml/xmlerror.h>
17
#include <libxml/parser.h>
18
#include <libxml/threads.h>
19
20
#include "private/error.h"
21
#include "private/memory.h"
22
#include "private/threads.h"
23
24
static unsigned long  debugMemSize = 0;
25
static unsigned long  debugMemBlocks = 0;
26
static xmlMutex xmlMemMutex;
27
28
/************************************************************************
29
 *                  *
30
 *    Macros, variables and associated types      *
31
 *                  *
32
 ************************************************************************/
33
34
/*
35
 * Each of the blocks allocated begin with a header containing information
36
 */
37
38
0
#define MEMTAG 0x5aa5U
39
40
typedef struct memnod {
41
    unsigned int   mh_tag;
42
    size_t         mh_size;
43
} MEMHDR;
44
45
#ifdef SUN4
46
#define ALIGN_SIZE  16
47
#else
48
0
#define ALIGN_SIZE  sizeof(double)
49
#endif
50
0
#define RESERVE_SIZE (((sizeof(MEMHDR) + ALIGN_SIZE - 1) \
51
0
          / ALIGN_SIZE ) * ALIGN_SIZE)
52
53
0
#define MAX_SIZE_T ((size_t)-1)
54
55
0
#define CLIENT_2_HDR(a) ((void *) (((char *) (a)) - RESERVE_SIZE))
56
0
#define HDR_2_CLIENT(a)    ((void *) (((char *) (a)) + RESERVE_SIZE))
57
58
/**
59
 * xmlMallocLoc:
60
 * @size:  an int specifying the size in byte to allocate.
61
 * @file:  the file name or NULL
62
 * @line:  the line number
63
 *
64
 * DEPRECATED: don't use
65
 *
66
 * Returns a pointer to the allocated area or NULL in case of lack of memory.
67
 */
68
void *
69
xmlMallocLoc(size_t size, const char *file ATTRIBUTE_UNUSED,
70
             int line ATTRIBUTE_UNUSED)
71
0
{
72
0
    return(xmlMemMalloc(size));
73
0
}
74
75
/**
76
 * xmlMallocAtomicLoc:
77
 * @size:  an unsigned int specifying the size in byte to allocate.
78
 * @file:  the file name or NULL
79
 * @line:  the line number
80
 *
81
 * DEPRECATED: don't use
82
 *
83
 * Returns a pointer to the allocated area or NULL in case of lack of memory.
84
 */
85
void *
86
xmlMallocAtomicLoc(size_t size, const char *file ATTRIBUTE_UNUSED,
87
                   int line ATTRIBUTE_UNUSED)
88
0
{
89
0
    return(xmlMemMalloc(size));
90
0
}
91
92
/**
93
 * xmlMemMalloc:
94
 * @size:  an int specifying the size in byte to allocate.
95
 *
96
 * a malloc() equivalent, with logging of the allocation info.
97
 *
98
 * Returns a pointer to the allocated area or NULL in case of lack of memory.
99
 */
100
void *
101
xmlMemMalloc(size_t size)
102
0
{
103
0
    MEMHDR *p;
104
105
0
    xmlInitParser();
106
107
0
    if (size > (MAX_SIZE_T - RESERVE_SIZE))
108
0
        return(NULL);
109
110
0
    p = (MEMHDR *) malloc(RESERVE_SIZE + size);
111
0
    if (!p)
112
0
        return(NULL);
113
0
    p->mh_tag = MEMTAG;
114
0
    p->mh_size = size;
115
116
0
    xmlMutexLock(&xmlMemMutex);
117
0
    debugMemSize += size;
118
0
    debugMemBlocks++;
119
0
    xmlMutexUnlock(&xmlMemMutex);
120
121
0
    return(HDR_2_CLIENT(p));
122
0
}
123
124
/**
125
 * xmlReallocLoc:
126
 * @ptr:  the initial memory block pointer
127
 * @size:  an int specifying the size in byte to allocate.
128
 * @file:  the file name or NULL
129
 * @line:  the line number
130
 *
131
 * DEPRECATED: don't use
132
 *
133
 * Returns a pointer to the allocated area or NULL in case of lack of memory.
134
 */
135
void *
136
xmlReallocLoc(void *ptr, size_t size, const char *file ATTRIBUTE_UNUSED,
137
              int line ATTRIBUTE_UNUSED)
138
0
{
139
0
    return(xmlMemRealloc(ptr, size));
140
0
}
141
142
/**
143
 * xmlMemRealloc:
144
 * @ptr:  the initial memory block pointer
145
 * @size:  an int specifying the size in byte to allocate.
146
 *
147
 * a realloc() equivalent, with logging of the allocation info.
148
 *
149
 * Returns a pointer to the allocated area or NULL in case of lack of memory.
150
 */
151
void *
152
0
xmlMemRealloc(void *ptr, size_t size) {
153
0
    MEMHDR *p, *tmp;
154
0
    size_t oldSize;
155
156
0
    if (ptr == NULL)
157
0
        return(xmlMemMalloc(size));
158
159
0
    xmlInitParser();
160
161
0
    if (size > (MAX_SIZE_T - RESERVE_SIZE))
162
0
        return(NULL);
163
164
0
    p = CLIENT_2_HDR(ptr);
165
0
    if (p->mh_tag != MEMTAG) {
166
0
        xmlPrintErrorMessage("xmlMemRealloc: Tag error\n");
167
0
        return(NULL);
168
0
    }
169
0
    oldSize = p->mh_size;
170
0
    p->mh_tag = ~MEMTAG;
171
172
0
    tmp = (MEMHDR *) realloc(p, RESERVE_SIZE + size);
173
0
    if (!tmp) {
174
0
        p->mh_tag = MEMTAG;
175
0
        return(NULL);
176
0
    }
177
0
    p = tmp;
178
0
    p->mh_tag = MEMTAG;
179
0
    p->mh_size = size;
180
181
0
    xmlMutexLock(&xmlMemMutex);
182
0
    debugMemSize -= oldSize;
183
0
    debugMemSize += size;
184
0
    xmlMutexUnlock(&xmlMemMutex);
185
186
0
    return(HDR_2_CLIENT(p));
187
0
}
188
189
/**
190
 * xmlMemFree:
191
 * @ptr:  the memory block pointer
192
 *
193
 * a free() equivalent, with error checking.
194
 */
195
void
196
xmlMemFree(void *ptr)
197
0
{
198
0
    MEMHDR *p;
199
200
0
    if (ptr == NULL)
201
0
        return;
202
203
0
    if (ptr == (void *) -1) {
204
0
        xmlPrintErrorMessage("xmlMemFree: Pointer from freed area\n");
205
0
        return;
206
0
    }
207
208
0
    p = CLIENT_2_HDR(ptr);
209
0
    if (p->mh_tag != MEMTAG) {
210
0
        xmlPrintErrorMessage("xmlMemFree: Tag error\n");
211
0
        return;
212
0
    }
213
0
    p->mh_tag = ~MEMTAG;
214
0
    memset(ptr, -1, p->mh_size);
215
216
0
    xmlMutexLock(&xmlMemMutex);
217
0
    debugMemSize -= p->mh_size;
218
0
    debugMemBlocks--;
219
0
    xmlMutexUnlock(&xmlMemMutex);
220
221
0
    free(p);
222
0
}
223
224
/**
225
 * xmlMemStrdupLoc:
226
 * @str:  the initial string pointer
227
 * @file:  the file name or NULL
228
 * @line:  the line number
229
 *
230
 * DEPRECATED: don't use
231
 *
232
 * Returns a pointer to the new string or NULL if allocation error occurred.
233
 */
234
char *
235
xmlMemStrdupLoc(const char *str, const char *file ATTRIBUTE_UNUSED,
236
                int line ATTRIBUTE_UNUSED)
237
0
{
238
0
    return(xmlMemoryStrdup(str));
239
0
}
240
241
/**
242
 * xmlMemoryStrdup:
243
 * @str:  the initial string pointer
244
 *
245
 * a strdup() equivalent, with logging of the allocation info.
246
 *
247
 * Returns a pointer to the new string or NULL if allocation error occurred.
248
 */
249
char *
250
0
xmlMemoryStrdup(const char *str) {
251
0
    char *s;
252
0
    size_t size = strlen(str) + 1;
253
0
    MEMHDR *p;
254
255
0
    xmlInitParser();
256
257
0
    if (size > (MAX_SIZE_T - RESERVE_SIZE))
258
0
        return(NULL);
259
260
0
    p = (MEMHDR *) malloc(RESERVE_SIZE + size);
261
0
    if (!p)
262
0
        return(NULL);
263
0
    p->mh_tag = MEMTAG;
264
0
    p->mh_size = size;
265
266
0
    xmlMutexLock(&xmlMemMutex);
267
0
    debugMemSize += size;
268
0
    debugMemBlocks++;
269
0
    xmlMutexUnlock(&xmlMemMutex);
270
271
0
    s = (char *) HDR_2_CLIENT(p);
272
273
0
    memcpy(s, str, size);
274
275
0
    return(s);
276
0
}
277
278
/**
279
 * xmlMemSize:
280
 * @ptr:  pointer to the memory allocation
281
 *
282
 * Returns the size of a memory allocation.
283
 */
284
285
size_t
286
0
xmlMemSize(void *ptr) {
287
0
    MEMHDR *p;
288
289
0
    if (ptr == NULL)
290
0
  return(0);
291
292
0
    p = CLIENT_2_HDR(ptr);
293
0
    if (p->mh_tag != MEMTAG)
294
0
        return(0);
295
296
0
    return(p->mh_size);
297
0
}
298
299
/**
300
 * xmlMemUsed:
301
 *
302
 * Provides the amount of memory currently allocated
303
 *
304
 * Returns an int representing the amount of memory allocated.
305
 */
306
307
int
308
0
xmlMemUsed(void) {
309
0
    return(debugMemSize);
310
0
}
311
312
/**
313
 * xmlMemBlocks:
314
 *
315
 * Provides the number of memory areas currently allocated
316
 *
317
 * Returns an int representing the number of blocks
318
 */
319
320
int
321
0
xmlMemBlocks(void) {
322
0
    int res;
323
324
0
    xmlMutexLock(&xmlMemMutex);
325
0
    res = debugMemBlocks;
326
0
    xmlMutexUnlock(&xmlMemMutex);
327
0
    return(res);
328
0
}
329
330
/**
331
 * xmlMemDisplayLast:
332
 * @fp:  a FILE descriptor
333
 * @nbBytes: the amount of memory to dump
334
 *
335
 * DEPRECATED: This feature was removed.
336
 */
337
void
338
xmlMemDisplayLast(FILE *fp ATTRIBUTE_UNUSED, long nbBytes ATTRIBUTE_UNUSED)
339
0
{
340
0
}
341
342
/**
343
 * xmlMemDisplay:
344
 * @fp:  a FILE descriptor
345
 *
346
 * DEPRECATED: This feature was removed.
347
 */
348
void
349
xmlMemDisplay(FILE *fp ATTRIBUTE_UNUSED)
350
0
{
351
0
}
352
353
/**
354
 * xmlMemShow:
355
 * @fp:  a FILE descriptor
356
 * @nr:  number of entries to dump
357
 *
358
 * DEPRECATED: This feature was removed.
359
 */
360
void
361
xmlMemShow(FILE *fp ATTRIBUTE_UNUSED, int nr ATTRIBUTE_UNUSED)
362
0
{
363
0
}
364
365
/**
366
 * xmlMemoryDump:
367
 *
368
 * DEPRECATED: This feature was removed.
369
 */
370
void
371
xmlMemoryDump(void)
372
0
{
373
0
}
374
375
376
/****************************************************************
377
 *                *
378
 *    Initialization Routines       *
379
 *                *
380
 ****************************************************************/
381
382
/**
383
 * xmlInitMemory:
384
 *
385
 * DEPRECATED: Alias for xmlInitParser.
386
 *
387
 * Returns 0.
388
 */
389
int
390
0
xmlInitMemory(void) {
391
0
    xmlInitParser();
392
0
    return(0);
393
0
}
394
395
/**
396
 * xmlInitMemoryInternal:
397
 *
398
 * Initialize the memory layer.
399
 */
400
void
401
9.89k
xmlInitMemoryInternal(void) {
402
9.89k
    xmlInitMutex(&xmlMemMutex);
403
9.89k
}
404
405
/**
406
 * xmlCleanupMemory:
407
 *
408
 * DEPRECATED: This function is a no-op. Call xmlCleanupParser
409
 * to free global state but see the warnings there. xmlCleanupParser
410
 * should be only called once at program exit. In most cases, you don't
411
 * have call cleanup functions at all.
412
 */
413
void
414
0
xmlCleanupMemory(void) {
415
0
}
416
417
/**
418
 * xmlCleanupMemoryInternal:
419
 *
420
 * Free up all the memory allocated by the library for its own
421
 * use. This should not be called by user level code.
422
 */
423
void
424
9.89k
xmlCleanupMemoryInternal(void) {
425
    /*
426
     * Don't clean up mutex on Windows. Global state destructors can call
427
     * malloc functions after xmlCleanupParser was called. If memory
428
     * debugging is enabled, xmlMemMutex can be used after cleanup.
429
     *
430
     * See python/tests/thread2.py
431
     */
432
9.89k
#if !defined(LIBXML_THREAD_ENABLED) || !defined(_WIN32)
433
9.89k
    xmlCleanupMutex(&xmlMemMutex);
434
9.89k
#endif
435
9.89k
}
436
437
/**
438
 * xmlMemSetup:
439
 * @freeFunc: the free() function to use
440
 * @mallocFunc: the malloc() function to use
441
 * @reallocFunc: the realloc() function to use
442
 * @strdupFunc: the strdup() function to use
443
 *
444
 * Override the default memory access functions with a new set
445
 * This has to be called before any other libxml routines !
446
 *
447
 * Should this be blocked if there was already some allocations
448
 * done ?
449
 *
450
 * Returns 0 on success
451
 */
452
int
453
xmlMemSetup(xmlFreeFunc freeFunc, xmlMallocFunc mallocFunc,
454
0
            xmlReallocFunc reallocFunc, xmlStrdupFunc strdupFunc) {
455
0
    if (freeFunc == NULL)
456
0
  return(-1);
457
0
    if (mallocFunc == NULL)
458
0
  return(-1);
459
0
    if (reallocFunc == NULL)
460
0
  return(-1);
461
0
    if (strdupFunc == NULL)
462
0
  return(-1);
463
0
    xmlFree = freeFunc;
464
0
    xmlMalloc = mallocFunc;
465
0
    xmlMallocAtomic = mallocFunc;
466
0
    xmlRealloc = reallocFunc;
467
0
    xmlMemStrdup = strdupFunc;
468
0
    return(0);
469
0
}
470
471
/**
472
 * xmlMemGet:
473
 * @freeFunc: place to save the free() function in use
474
 * @mallocFunc: place to save the malloc() function in use
475
 * @reallocFunc: place to save the realloc() function in use
476
 * @strdupFunc: place to save the strdup() function in use
477
 *
478
 * Provides the memory access functions set currently in use
479
 *
480
 * Returns 0 on success
481
 */
482
int
483
xmlMemGet(xmlFreeFunc *freeFunc, xmlMallocFunc *mallocFunc,
484
0
    xmlReallocFunc *reallocFunc, xmlStrdupFunc *strdupFunc) {
485
0
    if (freeFunc != NULL) *freeFunc = xmlFree;
486
0
    if (mallocFunc != NULL) *mallocFunc = xmlMalloc;
487
0
    if (reallocFunc != NULL) *reallocFunc = xmlRealloc;
488
0
    if (strdupFunc != NULL) *strdupFunc = xmlMemStrdup;
489
0
    return(0);
490
0
}
491
492
/**
493
 * xmlGcMemSetup:
494
 * @freeFunc: the free() function to use
495
 * @mallocFunc: the malloc() function to use
496
 * @mallocAtomicFunc: the malloc() function to use for atomic allocations
497
 * @reallocFunc: the realloc() function to use
498
 * @strdupFunc: the strdup() function to use
499
 *
500
 * DEPRECATED: Use xmlMemSetup.
501
 *
502
 * Override the default memory access functions with a new set
503
 * This has to be called before any other libxml routines !
504
 * The mallocAtomicFunc is specialized for atomic block
505
 * allocations (i.e. of areas  useful for garbage collected memory allocators
506
 *
507
 * Should this be blocked if there was already some allocations
508
 * done ?
509
 *
510
 * Returns 0 on success
511
 */
512
int
513
xmlGcMemSetup(xmlFreeFunc freeFunc, xmlMallocFunc mallocFunc,
514
              xmlMallocFunc mallocAtomicFunc, xmlReallocFunc reallocFunc,
515
0
        xmlStrdupFunc strdupFunc) {
516
0
    if (freeFunc == NULL)
517
0
  return(-1);
518
0
    if (mallocFunc == NULL)
519
0
  return(-1);
520
0
    if (mallocAtomicFunc == NULL)
521
0
  return(-1);
522
0
    if (reallocFunc == NULL)
523
0
  return(-1);
524
0
    if (strdupFunc == NULL)
525
0
  return(-1);
526
0
    xmlFree = freeFunc;
527
0
    xmlMalloc = mallocFunc;
528
0
    xmlMallocAtomic = mallocAtomicFunc;
529
0
    xmlRealloc = reallocFunc;
530
0
    xmlMemStrdup = strdupFunc;
531
0
    return(0);
532
0
}
533
534
/**
535
 * xmlGcMemGet:
536
 * @freeFunc: place to save the free() function in use
537
 * @mallocFunc: place to save the malloc() function in use
538
 * @mallocAtomicFunc: place to save the atomic malloc() function in use
539
 * @reallocFunc: place to save the realloc() function in use
540
 * @strdupFunc: place to save the strdup() function in use
541
 *
542
 * DEPRECATED: xmlMemGet.
543
 *
544
 * Provides the memory access functions set currently in use
545
 * The mallocAtomicFunc is specialized for atomic block
546
 * allocations (i.e. of areas  useful for garbage collected memory allocators
547
 *
548
 * Returns 0 on success
549
 */
550
int
551
xmlGcMemGet(xmlFreeFunc *freeFunc, xmlMallocFunc *mallocFunc,
552
            xmlMallocFunc *mallocAtomicFunc, xmlReallocFunc *reallocFunc,
553
0
      xmlStrdupFunc *strdupFunc) {
554
0
    if (freeFunc != NULL) *freeFunc = xmlFree;
555
0
    if (mallocFunc != NULL) *mallocFunc = xmlMalloc;
556
0
    if (mallocAtomicFunc != NULL) *mallocAtomicFunc = xmlMallocAtomic;
557
0
    if (reallocFunc != NULL) *reallocFunc = xmlRealloc;
558
0
    if (strdupFunc != NULL) *strdupFunc = xmlMemStrdup;
559
0
    return(0);
560
0
}
561