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