xref: /aosp_15_r20/external/libxml2/xmlmemory.c (revision 7c5688314b92172186c154356a6374bf7684c3ca)
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