Coverage Report

Created: 2025-07-01 06:27

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