• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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