1 /*
2 * xmlmemory.c: libxml memory allocator wrapper.
3 *
4 * [email protected]
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 #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 #define ALIGN_SIZE sizeof(double)
49 #endif
50 #define RESERVE_SIZE (((sizeof(MEMHDR) + ALIGN_SIZE - 1) \
51 / ALIGN_SIZE ) * ALIGN_SIZE)
52
53 #define MAX_SIZE_T ((size_t)-1)
54
55 #define CLIENT_2_HDR(a) ((void *) (((char *) (a)) - RESERVE_SIZE))
56 #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 *
xmlMallocLoc(size_t size,const char * file ATTRIBUTE_UNUSED,int line ATTRIBUTE_UNUSED)69 xmlMallocLoc(size_t size, const char *file ATTRIBUTE_UNUSED,
70 int line ATTRIBUTE_UNUSED)
71 {
72 return(xmlMemMalloc(size));
73 }
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 *
xmlMallocAtomicLoc(size_t size,const char * file ATTRIBUTE_UNUSED,int line ATTRIBUTE_UNUSED)86 xmlMallocAtomicLoc(size_t size, const char *file ATTRIBUTE_UNUSED,
87 int line ATTRIBUTE_UNUSED)
88 {
89 return(xmlMemMalloc(size));
90 }
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 *
xmlMemMalloc(size_t size)101 xmlMemMalloc(size_t size)
102 {
103 MEMHDR *p;
104
105 xmlInitParser();
106
107 if (size > (MAX_SIZE_T - RESERVE_SIZE))
108 return(NULL);
109
110 p = (MEMHDR *) malloc(RESERVE_SIZE + size);
111 if (!p)
112 return(NULL);
113 p->mh_tag = MEMTAG;
114 p->mh_size = size;
115
116 xmlMutexLock(&xmlMemMutex);
117 debugMemSize += size;
118 debugMemBlocks++;
119 xmlMutexUnlock(&xmlMemMutex);
120
121 return(HDR_2_CLIENT(p));
122 }
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 *
xmlReallocLoc(void * ptr,size_t size,const char * file ATTRIBUTE_UNUSED,int line ATTRIBUTE_UNUSED)136 xmlReallocLoc(void *ptr, size_t size, const char *file ATTRIBUTE_UNUSED,
137 int line ATTRIBUTE_UNUSED)
138 {
139 return(xmlMemRealloc(ptr, size));
140 }
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 *
xmlMemRealloc(void * ptr,size_t size)152 xmlMemRealloc(void *ptr, size_t size) {
153 MEMHDR *p, *tmp;
154 size_t oldSize;
155
156 if (ptr == NULL)
157 return(xmlMemMalloc(size));
158
159 xmlInitParser();
160
161 if (size > (MAX_SIZE_T - RESERVE_SIZE))
162 return(NULL);
163
164 p = CLIENT_2_HDR(ptr);
165 if (p->mh_tag != MEMTAG) {
166 xmlPrintErrorMessage("xmlMemRealloc: Tag error\n");
167 return(NULL);
168 }
169 oldSize = p->mh_size;
170 p->mh_tag = ~MEMTAG;
171
172 tmp = (MEMHDR *) realloc(p, RESERVE_SIZE + size);
173 if (!tmp) {
174 p->mh_tag = MEMTAG;
175 return(NULL);
176 }
177 p = tmp;
178 p->mh_tag = MEMTAG;
179 p->mh_size = size;
180
181 xmlMutexLock(&xmlMemMutex);
182 debugMemSize -= oldSize;
183 debugMemSize += size;
184 xmlMutexUnlock(&xmlMemMutex);
185
186 return(HDR_2_CLIENT(p));
187 }
188
189 /**
190 * xmlMemFree:
191 * @ptr: the memory block pointer
192 *
193 * a free() equivalent, with error checking.
194 */
195 void
xmlMemFree(void * ptr)196 xmlMemFree(void *ptr)
197 {
198 MEMHDR *p;
199
200 if (ptr == NULL)
201 return;
202
203 if (ptr == (void *) -1) {
204 xmlPrintErrorMessage("xmlMemFree: Pointer from freed area\n");
205 return;
206 }
207
208 p = CLIENT_2_HDR(ptr);
209 if (p->mh_tag != MEMTAG) {
210 xmlPrintErrorMessage("xmlMemFree: Tag error\n");
211 return;
212 }
213 p->mh_tag = ~MEMTAG;
214 memset(ptr, -1, p->mh_size);
215
216 xmlMutexLock(&xmlMemMutex);
217 debugMemSize -= p->mh_size;
218 debugMemBlocks--;
219 xmlMutexUnlock(&xmlMemMutex);
220
221 free(p);
222 }
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 *
xmlMemStrdupLoc(const char * str,const char * file ATTRIBUTE_UNUSED,int line ATTRIBUTE_UNUSED)235 xmlMemStrdupLoc(const char *str, const char *file ATTRIBUTE_UNUSED,
236 int line ATTRIBUTE_UNUSED)
237 {
238 return(xmlMemoryStrdup(str));
239 }
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 *
xmlMemoryStrdup(const char * str)250 xmlMemoryStrdup(const char *str) {
251 char *s;
252 size_t size = strlen(str) + 1;
253 MEMHDR *p;
254
255 xmlInitParser();
256
257 if (size > (MAX_SIZE_T - RESERVE_SIZE))
258 return(NULL);
259
260 p = (MEMHDR *) malloc(RESERVE_SIZE + size);
261 if (!p)
262 return(NULL);
263 p->mh_tag = MEMTAG;
264 p->mh_size = size;
265
266 xmlMutexLock(&xmlMemMutex);
267 debugMemSize += size;
268 debugMemBlocks++;
269 xmlMutexUnlock(&xmlMemMutex);
270
271 s = (char *) HDR_2_CLIENT(p);
272
273 memcpy(s, str, size);
274
275 return(s);
276 }
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
xmlMemSize(void * ptr)286 xmlMemSize(void *ptr) {
287 MEMHDR *p;
288
289 if (ptr == NULL)
290 return(0);
291
292 p = CLIENT_2_HDR(ptr);
293 if (p->mh_tag != MEMTAG)
294 return(0);
295
296 return(p->mh_size);
297 }
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
xmlMemUsed(void)308 xmlMemUsed(void) {
309 return(debugMemSize);
310 }
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
xmlMemBlocks(void)321 xmlMemBlocks(void) {
322 int res;
323
324 xmlMutexLock(&xmlMemMutex);
325 res = debugMemBlocks;
326 xmlMutexUnlock(&xmlMemMutex);
327 return(res);
328 }
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
xmlMemDisplayLast(FILE * fp ATTRIBUTE_UNUSED,long nbBytes ATTRIBUTE_UNUSED)338 xmlMemDisplayLast(FILE *fp ATTRIBUTE_UNUSED, long nbBytes ATTRIBUTE_UNUSED)
339 {
340 }
341
342 /**
343 * xmlMemDisplay:
344 * @fp: a FILE descriptor
345 *
346 * DEPRECATED: This feature was removed.
347 */
348 void
xmlMemDisplay(FILE * fp ATTRIBUTE_UNUSED)349 xmlMemDisplay(FILE *fp ATTRIBUTE_UNUSED)
350 {
351 }
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
xmlMemShow(FILE * fp ATTRIBUTE_UNUSED,int nr ATTRIBUTE_UNUSED)361 xmlMemShow(FILE *fp ATTRIBUTE_UNUSED, int nr ATTRIBUTE_UNUSED)
362 {
363 }
364
365 /**
366 * xmlMemoryDump:
367 *
368 * DEPRECATED: This feature was removed.
369 */
370 void
xmlMemoryDump(void)371 xmlMemoryDump(void)
372 {
373 }
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
xmlInitMemory(void)390 xmlInitMemory(void) {
391 xmlInitParser();
392 return(0);
393 }
394
395 /**
396 * xmlInitMemoryInternal:
397 *
398 * Initialize the memory layer.
399 */
400 void
xmlInitMemoryInternal(void)401 xmlInitMemoryInternal(void) {
402 xmlInitMutex(&xmlMemMutex);
403 }
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
xmlCleanupMemory(void)414 xmlCleanupMemory(void) {
415 }
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
xmlCleanupMemoryInternal(void)424 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 #if !defined(LIBXML_THREAD_ENABLED) || !defined(_WIN32)
433 xmlCleanupMutex(&xmlMemMutex);
434 #endif
435 }
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
xmlMemSetup(xmlFreeFunc freeFunc,xmlMallocFunc mallocFunc,xmlReallocFunc reallocFunc,xmlStrdupFunc strdupFunc)453 xmlMemSetup(xmlFreeFunc freeFunc, xmlMallocFunc mallocFunc,
454 xmlReallocFunc reallocFunc, xmlStrdupFunc strdupFunc) {
455 if (freeFunc == NULL)
456 return(-1);
457 if (mallocFunc == NULL)
458 return(-1);
459 if (reallocFunc == NULL)
460 return(-1);
461 if (strdupFunc == NULL)
462 return(-1);
463 xmlFree = freeFunc;
464 xmlMalloc = mallocFunc;
465 xmlMallocAtomic = mallocFunc;
466 xmlRealloc = reallocFunc;
467 xmlMemStrdup = strdupFunc;
468 return(0);
469 }
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
xmlMemGet(xmlFreeFunc * freeFunc,xmlMallocFunc * mallocFunc,xmlReallocFunc * reallocFunc,xmlStrdupFunc * strdupFunc)483 xmlMemGet(xmlFreeFunc *freeFunc, xmlMallocFunc *mallocFunc,
484 xmlReallocFunc *reallocFunc, xmlStrdupFunc *strdupFunc) {
485 if (freeFunc != NULL) *freeFunc = xmlFree;
486 if (mallocFunc != NULL) *mallocFunc = xmlMalloc;
487 if (reallocFunc != NULL) *reallocFunc = xmlRealloc;
488 if (strdupFunc != NULL) *strdupFunc = xmlMemStrdup;
489 return(0);
490 }
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
xmlGcMemSetup(xmlFreeFunc freeFunc,xmlMallocFunc mallocFunc,xmlMallocFunc mallocAtomicFunc,xmlReallocFunc reallocFunc,xmlStrdupFunc strdupFunc)513 xmlGcMemSetup(xmlFreeFunc freeFunc, xmlMallocFunc mallocFunc,
514 xmlMallocFunc mallocAtomicFunc, xmlReallocFunc reallocFunc,
515 xmlStrdupFunc strdupFunc) {
516 if (freeFunc == NULL)
517 return(-1);
518 if (mallocFunc == NULL)
519 return(-1);
520 if (mallocAtomicFunc == NULL)
521 return(-1);
522 if (reallocFunc == NULL)
523 return(-1);
524 if (strdupFunc == NULL)
525 return(-1);
526 xmlFree = freeFunc;
527 xmlMalloc = mallocFunc;
528 xmlMallocAtomic = mallocAtomicFunc;
529 xmlRealloc = reallocFunc;
530 xmlMemStrdup = strdupFunc;
531 return(0);
532 }
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
xmlGcMemGet(xmlFreeFunc * freeFunc,xmlMallocFunc * mallocFunc,xmlMallocFunc * mallocAtomicFunc,xmlReallocFunc * reallocFunc,xmlStrdupFunc * strdupFunc)551 xmlGcMemGet(xmlFreeFunc *freeFunc, xmlMallocFunc *mallocFunc,
552 xmlMallocFunc *mallocAtomicFunc, xmlReallocFunc *reallocFunc,
553 xmlStrdupFunc *strdupFunc) {
554 if (freeFunc != NULL) *freeFunc = xmlFree;
555 if (mallocFunc != NULL) *mallocFunc = xmlMalloc;
556 if (mallocAtomicFunc != NULL) *mallocAtomicFunc = xmlMallocAtomic;
557 if (reallocFunc != NULL) *reallocFunc = xmlRealloc;
558 if (strdupFunc != NULL) *strdupFunc = xmlMemStrdup;
559 return(0);
560 }
561
562