/src/libxml2-2.9.7/xmlmemory.c
Line | Count | Source (jump to first uncovered line) |
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 | | |
12 | | #ifdef HAVE_SYS_TYPES_H |
13 | | #include <sys/types.h> |
14 | | #endif |
15 | | |
16 | | #ifdef HAVE_TIME_H |
17 | | #include <time.h> |
18 | | #endif |
19 | | |
20 | | #ifdef HAVE_STDLIB_H |
21 | | #include <stdlib.h> |
22 | | #else |
23 | | #ifdef HAVE_MALLOC_H |
24 | | #include <malloc.h> |
25 | | #endif |
26 | | #endif |
27 | | |
28 | | #ifdef HAVE_CTYPE_H |
29 | | #include <ctype.h> |
30 | | #endif |
31 | | |
32 | | /* #define DEBUG_MEMORY */ |
33 | | |
34 | | /** |
35 | | * MEM_LIST: |
36 | | * |
37 | | * keep track of all allocated blocks for error reporting |
38 | | * Always build the memory list ! |
39 | | */ |
40 | | #ifdef DEBUG_MEMORY_LOCATION |
41 | | #ifndef MEM_LIST |
42 | | #define MEM_LIST /* keep a list of all the allocated memory blocks */ |
43 | | #endif |
44 | | #endif |
45 | | |
46 | | #include <libxml/globals.h> /* must come before xmlmemory.h */ |
47 | | #include <libxml/xmlmemory.h> |
48 | | #include <libxml/xmlerror.h> |
49 | | #include <libxml/threads.h> |
50 | | |
51 | | static int xmlMemInitialized = 0; |
52 | | static unsigned long debugMemSize = 0; |
53 | | static unsigned long debugMemBlocks = 0; |
54 | | static unsigned long debugMaxMemSize = 0; |
55 | | static xmlMutexPtr xmlMemMutex = NULL; |
56 | | |
57 | | void xmlMallocBreakpoint(void); |
58 | | |
59 | | /************************************************************************ |
60 | | * * |
61 | | * Macros, variables and associated types * |
62 | | * * |
63 | | ************************************************************************/ |
64 | | |
65 | | #if !defined(LIBXML_THREAD_ENABLED) && !defined(LIBXML_THREAD_ALLOC_ENABLED) |
66 | | #ifdef xmlMalloc |
67 | | #undef xmlMalloc |
68 | | #endif |
69 | | #ifdef xmlRealloc |
70 | | #undef xmlRealloc |
71 | | #endif |
72 | | #ifdef xmlMemStrdup |
73 | | #undef xmlMemStrdup |
74 | | #endif |
75 | | #endif |
76 | | |
77 | | /* |
78 | | * Each of the blocks allocated begin with a header containing informations |
79 | | */ |
80 | | |
81 | 0 | #define MEMTAG 0x5aa5 |
82 | | |
83 | 0 | #define MALLOC_TYPE 1 |
84 | 0 | #define REALLOC_TYPE 2 |
85 | 0 | #define STRDUP_TYPE 3 |
86 | 0 | #define MALLOC_ATOMIC_TYPE 4 |
87 | | #define REALLOC_ATOMIC_TYPE 5 |
88 | | |
89 | | typedef struct memnod { |
90 | | unsigned int mh_tag; |
91 | | unsigned int mh_type; |
92 | | unsigned long mh_number; |
93 | | size_t mh_size; |
94 | | #ifdef MEM_LIST |
95 | | struct memnod *mh_next; |
96 | | struct memnod *mh_prev; |
97 | | #endif |
98 | | const char *mh_file; |
99 | | unsigned int mh_line; |
100 | | } MEMHDR; |
101 | | |
102 | | |
103 | | #ifdef SUN4 |
104 | | #define ALIGN_SIZE 16 |
105 | | #else |
106 | 0 | #define ALIGN_SIZE sizeof(double) |
107 | | #endif |
108 | 0 | #define HDR_SIZE sizeof(MEMHDR) |
109 | 0 | #define RESERVE_SIZE (((HDR_SIZE + (ALIGN_SIZE-1)) \ |
110 | 0 | / ALIGN_SIZE ) * ALIGN_SIZE) |
111 | | |
112 | 0 | #define MAX_SIZE_T ((size_t)-1) |
113 | | |
114 | 0 | #define CLIENT_2_HDR(a) ((void *) (((char *) (a)) - RESERVE_SIZE)) |
115 | 0 | #define HDR_2_CLIENT(a) ((void *) (((char *) (a)) + RESERVE_SIZE)) |
116 | | |
117 | | |
118 | | static unsigned int block=0; |
119 | | static unsigned int xmlMemStopAtBlock = 0; |
120 | | static void *xmlMemTraceBlockAt = NULL; |
121 | | #ifdef MEM_LIST |
122 | | static MEMHDR *memlist = NULL; |
123 | | #endif |
124 | | |
125 | | static void debugmem_tag_error(void *addr); |
126 | | #ifdef MEM_LIST |
127 | | static void debugmem_list_add(MEMHDR *); |
128 | | static void debugmem_list_delete(MEMHDR *); |
129 | | #endif |
130 | 0 | #define Mem_Tag_Err(a) debugmem_tag_error(a); |
131 | | |
132 | | #ifndef TEST_POINT |
133 | | #define TEST_POINT |
134 | | #endif |
135 | | |
136 | | /** |
137 | | * xmlMallocBreakpoint: |
138 | | * |
139 | | * Breakpoint to use in conjunction with xmlMemStopAtBlock. When the block |
140 | | * number reaches the specified value this function is called. One need to add a breakpoint |
141 | | * to it to get the context in which the given block is allocated. |
142 | | */ |
143 | | |
144 | | void |
145 | 0 | xmlMallocBreakpoint(void) { |
146 | 0 | xmlGenericError(xmlGenericErrorContext, |
147 | 0 | "xmlMallocBreakpoint reached on block %d\n", xmlMemStopAtBlock); |
148 | 0 | } |
149 | | |
150 | | /** |
151 | | * xmlMallocLoc: |
152 | | * @size: an int specifying the size in byte to allocate. |
153 | | * @file: the file name or NULL |
154 | | * @line: the line number |
155 | | * |
156 | | * a malloc() equivalent, with logging of the allocation info. |
157 | | * |
158 | | * Returns a pointer to the allocated area or NULL in case of lack of memory. |
159 | | */ |
160 | | |
161 | | void * |
162 | | xmlMallocLoc(size_t size, const char * file, int line) |
163 | 0 | { |
164 | 0 | MEMHDR *p; |
165 | 0 | void *ret; |
166 | |
|
167 | 0 | if (!xmlMemInitialized) xmlInitMemory(); |
168 | | #ifdef DEBUG_MEMORY |
169 | | xmlGenericError(xmlGenericErrorContext, |
170 | | "Malloc(%d)\n",size); |
171 | | #endif |
172 | | |
173 | | TEST_POINT |
174 | |
|
175 | 0 | if (size > (MAX_SIZE_T - RESERVE_SIZE)) { |
176 | 0 | xmlGenericError(xmlGenericErrorContext, |
177 | 0 | "xmlMallocLoc : Unsigned overflow\n"); |
178 | 0 | xmlMemoryDump(); |
179 | 0 | return(NULL); |
180 | 0 | } |
181 | | |
182 | 0 | p = (MEMHDR *) malloc(RESERVE_SIZE+size); |
183 | |
|
184 | 0 | if (!p) { |
185 | 0 | xmlGenericError(xmlGenericErrorContext, |
186 | 0 | "xmlMallocLoc : Out of free space\n"); |
187 | 0 | xmlMemoryDump(); |
188 | 0 | return(NULL); |
189 | 0 | } |
190 | 0 | p->mh_tag = MEMTAG; |
191 | 0 | p->mh_size = size; |
192 | 0 | p->mh_type = MALLOC_TYPE; |
193 | 0 | p->mh_file = file; |
194 | 0 | p->mh_line = line; |
195 | 0 | xmlMutexLock(xmlMemMutex); |
196 | 0 | p->mh_number = ++block; |
197 | 0 | debugMemSize += size; |
198 | 0 | debugMemBlocks++; |
199 | 0 | if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize; |
200 | | #ifdef MEM_LIST |
201 | | debugmem_list_add(p); |
202 | | #endif |
203 | 0 | xmlMutexUnlock(xmlMemMutex); |
204 | |
|
205 | | #ifdef DEBUG_MEMORY |
206 | | xmlGenericError(xmlGenericErrorContext, |
207 | | "Malloc(%d) Ok\n",size); |
208 | | #endif |
209 | |
|
210 | 0 | if (xmlMemStopAtBlock == p->mh_number) xmlMallocBreakpoint(); |
211 | |
|
212 | 0 | ret = HDR_2_CLIENT(p); |
213 | |
|
214 | 0 | if (xmlMemTraceBlockAt == ret) { |
215 | 0 | xmlGenericError(xmlGenericErrorContext, |
216 | 0 | "%p : Malloc(%lu) Ok\n", xmlMemTraceBlockAt, |
217 | 0 | (long unsigned)size); |
218 | 0 | xmlMallocBreakpoint(); |
219 | 0 | } |
220 | | |
221 | | TEST_POINT |
222 | |
|
223 | 0 | return(ret); |
224 | 0 | } |
225 | | |
226 | | /** |
227 | | * xmlMallocAtomicLoc: |
228 | | * @size: an unsigned int specifying the size in byte to allocate. |
229 | | * @file: the file name or NULL |
230 | | * @line: the line number |
231 | | * |
232 | | * a malloc() equivalent, with logging of the allocation info. |
233 | | * |
234 | | * Returns a pointer to the allocated area or NULL in case of lack of memory. |
235 | | */ |
236 | | |
237 | | void * |
238 | | xmlMallocAtomicLoc(size_t size, const char * file, int line) |
239 | 0 | { |
240 | 0 | MEMHDR *p; |
241 | 0 | void *ret; |
242 | |
|
243 | 0 | if (!xmlMemInitialized) xmlInitMemory(); |
244 | | #ifdef DEBUG_MEMORY |
245 | | xmlGenericError(xmlGenericErrorContext, |
246 | | "Malloc(%d)\n",size); |
247 | | #endif |
248 | | |
249 | | TEST_POINT |
250 | |
|
251 | 0 | if (size > (MAX_SIZE_T - RESERVE_SIZE)) { |
252 | 0 | xmlGenericError(xmlGenericErrorContext, |
253 | 0 | "xmlMallocAtomicLoc : Unsigned overflow\n"); |
254 | 0 | xmlMemoryDump(); |
255 | 0 | return(NULL); |
256 | 0 | } |
257 | | |
258 | 0 | p = (MEMHDR *) malloc(RESERVE_SIZE+size); |
259 | |
|
260 | 0 | if (!p) { |
261 | 0 | xmlGenericError(xmlGenericErrorContext, |
262 | 0 | "xmlMallocAtomicLoc : Out of free space\n"); |
263 | 0 | xmlMemoryDump(); |
264 | 0 | return(NULL); |
265 | 0 | } |
266 | 0 | p->mh_tag = MEMTAG; |
267 | 0 | p->mh_size = size; |
268 | 0 | p->mh_type = MALLOC_ATOMIC_TYPE; |
269 | 0 | p->mh_file = file; |
270 | 0 | p->mh_line = line; |
271 | 0 | xmlMutexLock(xmlMemMutex); |
272 | 0 | p->mh_number = ++block; |
273 | 0 | debugMemSize += size; |
274 | 0 | debugMemBlocks++; |
275 | 0 | if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize; |
276 | | #ifdef MEM_LIST |
277 | | debugmem_list_add(p); |
278 | | #endif |
279 | 0 | xmlMutexUnlock(xmlMemMutex); |
280 | |
|
281 | | #ifdef DEBUG_MEMORY |
282 | | xmlGenericError(xmlGenericErrorContext, |
283 | | "Malloc(%d) Ok\n",size); |
284 | | #endif |
285 | |
|
286 | 0 | if (xmlMemStopAtBlock == p->mh_number) xmlMallocBreakpoint(); |
287 | |
|
288 | 0 | ret = HDR_2_CLIENT(p); |
289 | |
|
290 | 0 | if (xmlMemTraceBlockAt == ret) { |
291 | 0 | xmlGenericError(xmlGenericErrorContext, |
292 | 0 | "%p : Malloc(%lu) Ok\n", xmlMemTraceBlockAt, |
293 | 0 | (long unsigned)size); |
294 | 0 | xmlMallocBreakpoint(); |
295 | 0 | } |
296 | | |
297 | | TEST_POINT |
298 | |
|
299 | 0 | return(ret); |
300 | 0 | } |
301 | | /** |
302 | | * xmlMemMalloc: |
303 | | * @size: an int specifying the size in byte to allocate. |
304 | | * |
305 | | * a malloc() equivalent, with logging of the allocation info. |
306 | | * |
307 | | * Returns a pointer to the allocated area or NULL in case of lack of memory. |
308 | | */ |
309 | | |
310 | | void * |
311 | | xmlMemMalloc(size_t size) |
312 | 0 | { |
313 | 0 | return(xmlMallocLoc(size, "none", 0)); |
314 | 0 | } |
315 | | |
316 | | /** |
317 | | * xmlReallocLoc: |
318 | | * @ptr: the initial memory block pointer |
319 | | * @size: an int specifying the size in byte to allocate. |
320 | | * @file: the file name or NULL |
321 | | * @line: the line number |
322 | | * |
323 | | * a realloc() equivalent, with logging of the allocation info. |
324 | | * |
325 | | * Returns a pointer to the allocated area or NULL in case of lack of memory. |
326 | | */ |
327 | | |
328 | | void * |
329 | | xmlReallocLoc(void *ptr,size_t size, const char * file, int line) |
330 | 0 | { |
331 | 0 | MEMHDR *p, *tmp; |
332 | 0 | unsigned long number; |
333 | | #ifdef DEBUG_MEMORY |
334 | | size_t oldsize; |
335 | | #endif |
336 | |
|
337 | 0 | if (ptr == NULL) |
338 | 0 | return(xmlMallocLoc(size, file, line)); |
339 | | |
340 | 0 | if (!xmlMemInitialized) xmlInitMemory(); |
341 | 0 | TEST_POINT |
342 | |
|
343 | 0 | p = CLIENT_2_HDR(ptr); |
344 | 0 | number = p->mh_number; |
345 | 0 | if (xmlMemStopAtBlock == number) xmlMallocBreakpoint(); |
346 | 0 | if (p->mh_tag != MEMTAG) { |
347 | 0 | Mem_Tag_Err(p); |
348 | 0 | goto error; |
349 | 0 | } |
350 | 0 | p->mh_tag = ~MEMTAG; |
351 | 0 | xmlMutexLock(xmlMemMutex); |
352 | 0 | debugMemSize -= p->mh_size; |
353 | 0 | debugMemBlocks--; |
354 | | #ifdef DEBUG_MEMORY |
355 | | oldsize = p->mh_size; |
356 | | #endif |
357 | | #ifdef MEM_LIST |
358 | | debugmem_list_delete(p); |
359 | | #endif |
360 | 0 | xmlMutexUnlock(xmlMemMutex); |
361 | |
|
362 | 0 | if (size > (MAX_SIZE_T - RESERVE_SIZE)) { |
363 | 0 | xmlGenericError(xmlGenericErrorContext, |
364 | 0 | "xmlReallocLoc : Unsigned overflow\n"); |
365 | 0 | xmlMemoryDump(); |
366 | 0 | return(NULL); |
367 | 0 | } |
368 | | |
369 | 0 | tmp = (MEMHDR *) realloc(p,RESERVE_SIZE+size); |
370 | 0 | if (!tmp) { |
371 | 0 | free(p); |
372 | 0 | goto error; |
373 | 0 | } |
374 | 0 | p = tmp; |
375 | 0 | if (xmlMemTraceBlockAt == ptr) { |
376 | 0 | xmlGenericError(xmlGenericErrorContext, |
377 | 0 | "%p : Realloced(%lu -> %lu) Ok\n", |
378 | 0 | xmlMemTraceBlockAt, (long unsigned)p->mh_size, |
379 | 0 | (long unsigned)size); |
380 | 0 | xmlMallocBreakpoint(); |
381 | 0 | } |
382 | 0 | p->mh_tag = MEMTAG; |
383 | 0 | p->mh_number = number; |
384 | 0 | p->mh_type = REALLOC_TYPE; |
385 | 0 | p->mh_size = size; |
386 | 0 | p->mh_file = file; |
387 | 0 | p->mh_line = line; |
388 | 0 | xmlMutexLock(xmlMemMutex); |
389 | 0 | debugMemSize += size; |
390 | 0 | debugMemBlocks++; |
391 | 0 | if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize; |
392 | | #ifdef MEM_LIST |
393 | | debugmem_list_add(p); |
394 | | #endif |
395 | 0 | xmlMutexUnlock(xmlMemMutex); |
396 | | |
397 | | TEST_POINT |
398 | |
|
399 | | #ifdef DEBUG_MEMORY |
400 | | xmlGenericError(xmlGenericErrorContext, |
401 | | "Realloced(%d to %d) Ok\n", oldsize, size); |
402 | | #endif |
403 | 0 | return(HDR_2_CLIENT(p)); |
404 | | |
405 | 0 | error: |
406 | 0 | return(NULL); |
407 | 0 | } |
408 | | |
409 | | /** |
410 | | * xmlMemRealloc: |
411 | | * @ptr: the initial memory block pointer |
412 | | * @size: an int specifying the size in byte to allocate. |
413 | | * |
414 | | * a realloc() equivalent, with logging of the allocation info. |
415 | | * |
416 | | * Returns a pointer to the allocated area or NULL in case of lack of memory. |
417 | | */ |
418 | | |
419 | | void * |
420 | 0 | xmlMemRealloc(void *ptr,size_t size) { |
421 | 0 | return(xmlReallocLoc(ptr, size, "none", 0)); |
422 | 0 | } |
423 | | |
424 | | /** |
425 | | * xmlMemFree: |
426 | | * @ptr: the memory block pointer |
427 | | * |
428 | | * a free() equivalent, with error checking. |
429 | | */ |
430 | | void |
431 | | xmlMemFree(void *ptr) |
432 | 0 | { |
433 | 0 | MEMHDR *p; |
434 | 0 | char *target; |
435 | | #ifdef DEBUG_MEMORY |
436 | | size_t size; |
437 | | #endif |
438 | |
|
439 | 0 | if (ptr == NULL) |
440 | 0 | return; |
441 | | |
442 | 0 | if (ptr == (void *) -1) { |
443 | 0 | xmlGenericError(xmlGenericErrorContext, |
444 | 0 | "trying to free pointer from freed area\n"); |
445 | 0 | goto error; |
446 | 0 | } |
447 | | |
448 | 0 | if (xmlMemTraceBlockAt == ptr) { |
449 | 0 | xmlGenericError(xmlGenericErrorContext, |
450 | 0 | "%p : Freed()\n", xmlMemTraceBlockAt); |
451 | 0 | xmlMallocBreakpoint(); |
452 | 0 | } |
453 | | |
454 | | TEST_POINT |
455 | |
|
456 | 0 | target = (char *) ptr; |
457 | |
|
458 | 0 | p = CLIENT_2_HDR(ptr); |
459 | 0 | if (p->mh_tag != MEMTAG) { |
460 | 0 | Mem_Tag_Err(p); |
461 | 0 | goto error; |
462 | 0 | } |
463 | 0 | if (xmlMemStopAtBlock == p->mh_number) xmlMallocBreakpoint(); |
464 | 0 | p->mh_tag = ~MEMTAG; |
465 | 0 | memset(target, -1, p->mh_size); |
466 | 0 | xmlMutexLock(xmlMemMutex); |
467 | 0 | debugMemSize -= p->mh_size; |
468 | 0 | debugMemBlocks--; |
469 | | #ifdef DEBUG_MEMORY |
470 | | size = p->mh_size; |
471 | | #endif |
472 | | #ifdef MEM_LIST |
473 | | debugmem_list_delete(p); |
474 | | #endif |
475 | 0 | xmlMutexUnlock(xmlMemMutex); |
476 | |
|
477 | 0 | free(p); |
478 | | |
479 | | TEST_POINT |
480 | |
|
481 | | #ifdef DEBUG_MEMORY |
482 | | xmlGenericError(xmlGenericErrorContext, |
483 | | "Freed(%d) Ok\n", size); |
484 | | #endif |
485 | |
|
486 | 0 | return; |
487 | | |
488 | 0 | error: |
489 | 0 | xmlGenericError(xmlGenericErrorContext, |
490 | 0 | "xmlMemFree(%p) error\n", ptr); |
491 | 0 | xmlMallocBreakpoint(); |
492 | 0 | return; |
493 | 0 | } |
494 | | |
495 | | /** |
496 | | * xmlMemStrdupLoc: |
497 | | * @str: the initial string pointer |
498 | | * @file: the file name or NULL |
499 | | * @line: the line number |
500 | | * |
501 | | * a strdup() equivalent, with logging of the allocation info. |
502 | | * |
503 | | * Returns a pointer to the new string or NULL if allocation error occurred. |
504 | | */ |
505 | | |
506 | | char * |
507 | | xmlMemStrdupLoc(const char *str, const char *file, int line) |
508 | 0 | { |
509 | 0 | char *s; |
510 | 0 | size_t size = strlen(str) + 1; |
511 | 0 | MEMHDR *p; |
512 | |
|
513 | 0 | if (!xmlMemInitialized) xmlInitMemory(); |
514 | 0 | TEST_POINT |
515 | |
|
516 | 0 | if (size > (MAX_SIZE_T - RESERVE_SIZE)) { |
517 | 0 | xmlGenericError(xmlGenericErrorContext, |
518 | 0 | "xmlMemStrdupLoc : Unsigned overflow\n"); |
519 | 0 | xmlMemoryDump(); |
520 | 0 | return(NULL); |
521 | 0 | } |
522 | | |
523 | 0 | p = (MEMHDR *) malloc(RESERVE_SIZE+size); |
524 | 0 | if (!p) { |
525 | 0 | goto error; |
526 | 0 | } |
527 | 0 | p->mh_tag = MEMTAG; |
528 | 0 | p->mh_size = size; |
529 | 0 | p->mh_type = STRDUP_TYPE; |
530 | 0 | p->mh_file = file; |
531 | 0 | p->mh_line = line; |
532 | 0 | xmlMutexLock(xmlMemMutex); |
533 | 0 | p->mh_number = ++block; |
534 | 0 | debugMemSize += size; |
535 | 0 | debugMemBlocks++; |
536 | 0 | if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize; |
537 | | #ifdef MEM_LIST |
538 | | debugmem_list_add(p); |
539 | | #endif |
540 | 0 | xmlMutexUnlock(xmlMemMutex); |
541 | |
|
542 | 0 | s = (char *) HDR_2_CLIENT(p); |
543 | |
|
544 | 0 | if (xmlMemStopAtBlock == p->mh_number) xmlMallocBreakpoint(); |
545 | |
|
546 | 0 | strcpy(s,str); |
547 | | |
548 | | TEST_POINT |
549 | |
|
550 | 0 | if (xmlMemTraceBlockAt == s) { |
551 | 0 | xmlGenericError(xmlGenericErrorContext, |
552 | 0 | "%p : Strdup() Ok\n", xmlMemTraceBlockAt); |
553 | 0 | xmlMallocBreakpoint(); |
554 | 0 | } |
555 | |
|
556 | 0 | return(s); |
557 | | |
558 | 0 | error: |
559 | 0 | return(NULL); |
560 | 0 | } |
561 | | |
562 | | /** |
563 | | * xmlMemoryStrdup: |
564 | | * @str: the initial string pointer |
565 | | * |
566 | | * a strdup() equivalent, with logging of the allocation info. |
567 | | * |
568 | | * Returns a pointer to the new string or NULL if allocation error occurred. |
569 | | */ |
570 | | |
571 | | char * |
572 | 0 | xmlMemoryStrdup(const char *str) { |
573 | 0 | return(xmlMemStrdupLoc(str, "none", 0)); |
574 | 0 | } |
575 | | |
576 | | /** |
577 | | * xmlMemUsed: |
578 | | * |
579 | | * Provides the amount of memory currently allocated |
580 | | * |
581 | | * Returns an int representing the amount of memory allocated. |
582 | | */ |
583 | | |
584 | | int |
585 | 0 | xmlMemUsed(void) { |
586 | 0 | int res; |
587 | |
|
588 | 0 | xmlMutexLock(xmlMemMutex); |
589 | 0 | res = debugMemSize; |
590 | 0 | xmlMutexUnlock(xmlMemMutex); |
591 | 0 | return(res); |
592 | 0 | } |
593 | | |
594 | | /** |
595 | | * xmlMemBlocks: |
596 | | * |
597 | | * Provides the number of memory areas currently allocated |
598 | | * |
599 | | * Returns an int representing the number of blocks |
600 | | */ |
601 | | |
602 | | int |
603 | 0 | xmlMemBlocks(void) { |
604 | 0 | int res; |
605 | |
|
606 | 0 | xmlMutexLock(xmlMemMutex); |
607 | 0 | res = debugMemBlocks; |
608 | 0 | xmlMutexUnlock(xmlMemMutex); |
609 | 0 | return(res); |
610 | 0 | } |
611 | | |
612 | | #ifdef MEM_LIST |
613 | | /** |
614 | | * xmlMemContentShow: |
615 | | * @fp: a FILE descriptor used as the output file |
616 | | * @p: a memory block header |
617 | | * |
618 | | * tries to show some content from the memory block |
619 | | */ |
620 | | |
621 | | static void |
622 | | xmlMemContentShow(FILE *fp, MEMHDR *p) |
623 | | { |
624 | | int i,j,k,len; |
625 | | const char *buf; |
626 | | |
627 | | if (p == NULL) { |
628 | | fprintf(fp, " NULL"); |
629 | | return; |
630 | | } |
631 | | len = p->mh_size; |
632 | | buf = (const char *) HDR_2_CLIENT(p); |
633 | | |
634 | | for (i = 0;i < len;i++) { |
635 | | if (buf[i] == 0) break; |
636 | | if (!isprint((unsigned char) buf[i])) break; |
637 | | } |
638 | | if ((i < 4) && ((buf[i] != 0) || (i == 0))) { |
639 | | if (len >= 4) { |
640 | | MEMHDR *q; |
641 | | void *cur; |
642 | | |
643 | | for (j = 0;(j < len -3) && (j < 40);j += 4) { |
644 | | cur = *((void **) &buf[j]); |
645 | | q = CLIENT_2_HDR(cur); |
646 | | p = memlist; |
647 | | k = 0; |
648 | | while (p != NULL) { |
649 | | if (p == q) break; |
650 | | p = p->mh_next; |
651 | | if (k++ > 100) break; |
652 | | } |
653 | | if ((p != NULL) && (p == q)) { |
654 | | fprintf(fp, " pointer to #%lu at index %d", |
655 | | p->mh_number, j); |
656 | | return; |
657 | | } |
658 | | } |
659 | | } |
660 | | } else if ((i == 0) && (buf[i] == 0)) { |
661 | | fprintf(fp," null"); |
662 | | } else { |
663 | | if (buf[i] == 0) fprintf(fp," \"%.25s\"", buf); |
664 | | else { |
665 | | fprintf(fp," ["); |
666 | | for (j = 0;j < i;j++) |
667 | | fprintf(fp,"%c", buf[j]); |
668 | | fprintf(fp,"]"); |
669 | | } |
670 | | } |
671 | | } |
672 | | #endif |
673 | | |
674 | | /** |
675 | | * xmlMemDisplayLast: |
676 | | * @fp: a FILE descriptor used as the output file, if NULL, the result is |
677 | | * written to the file .memorylist |
678 | | * @nbBytes: the amount of memory to dump |
679 | | * |
680 | | * the last nbBytes of memory allocated and not freed, useful for dumping |
681 | | * the memory left allocated between two places at runtime. |
682 | | */ |
683 | | |
684 | | void |
685 | | xmlMemDisplayLast(FILE *fp, long nbBytes) |
686 | 0 | { |
687 | | #ifdef MEM_LIST |
688 | | MEMHDR *p; |
689 | | unsigned idx; |
690 | | int nb = 0; |
691 | | #endif |
692 | 0 | FILE *old_fp = fp; |
693 | |
|
694 | 0 | if (nbBytes <= 0) |
695 | 0 | return; |
696 | | |
697 | 0 | if (fp == NULL) { |
698 | 0 | fp = fopen(".memorylist", "w"); |
699 | 0 | if (fp == NULL) |
700 | 0 | return; |
701 | 0 | } |
702 | | |
703 | | #ifdef MEM_LIST |
704 | | fprintf(fp," Last %li MEMORY ALLOCATED : %lu, MAX was %lu\n", |
705 | | nbBytes, debugMemSize, debugMaxMemSize); |
706 | | fprintf(fp,"BLOCK NUMBER SIZE TYPE\n"); |
707 | | idx = 0; |
708 | | xmlMutexLock(xmlMemMutex); |
709 | | p = memlist; |
710 | | while ((p) && (nbBytes > 0)) { |
711 | | fprintf(fp,"%-5u %6lu %6lu ",idx++,p->mh_number, |
712 | | (unsigned long)p->mh_size); |
713 | | switch (p->mh_type) { |
714 | | case STRDUP_TYPE:fprintf(fp,"strdup() in ");break; |
715 | | case MALLOC_TYPE:fprintf(fp,"malloc() in ");break; |
716 | | case REALLOC_TYPE:fprintf(fp,"realloc() in ");break; |
717 | | case MALLOC_ATOMIC_TYPE:fprintf(fp,"atomicmalloc() in ");break; |
718 | | case REALLOC_ATOMIC_TYPE:fprintf(fp,"atomicrealloc() in ");break; |
719 | | default: |
720 | | fprintf(fp,"Unknown memory block, may be corrupted"); |
721 | | xmlMutexUnlock(xmlMemMutex); |
722 | | if (old_fp == NULL) |
723 | | fclose(fp); |
724 | | return; |
725 | | } |
726 | | if (p->mh_file != NULL) fprintf(fp,"%s(%u)", p->mh_file, p->mh_line); |
727 | | if (p->mh_tag != MEMTAG) |
728 | | fprintf(fp," INVALID"); |
729 | | nb++; |
730 | | if (nb < 100) |
731 | | xmlMemContentShow(fp, p); |
732 | | else |
733 | | fprintf(fp," skip"); |
734 | | |
735 | | fprintf(fp,"\n"); |
736 | | nbBytes -= (unsigned long)p->mh_size; |
737 | | p = p->mh_next; |
738 | | } |
739 | | xmlMutexUnlock(xmlMemMutex); |
740 | | #else |
741 | 0 | fprintf(fp,"Memory list not compiled (MEM_LIST not defined !)\n"); |
742 | 0 | #endif |
743 | 0 | if (old_fp == NULL) |
744 | 0 | fclose(fp); |
745 | 0 | } |
746 | | |
747 | | /** |
748 | | * xmlMemDisplay: |
749 | | * @fp: a FILE descriptor used as the output file, if NULL, the result is |
750 | | * written to the file .memorylist |
751 | | * |
752 | | * show in-extenso the memory blocks allocated |
753 | | */ |
754 | | |
755 | | void |
756 | | xmlMemDisplay(FILE *fp) |
757 | 0 | { |
758 | | #ifdef MEM_LIST |
759 | | MEMHDR *p; |
760 | | unsigned idx; |
761 | | int nb = 0; |
762 | | #if defined(HAVE_LOCALTIME) && defined(HAVE_STRFTIME) |
763 | | time_t currentTime; |
764 | | char buf[500]; |
765 | | struct tm * tstruct; |
766 | | #endif |
767 | | #endif |
768 | 0 | FILE *old_fp = fp; |
769 | |
|
770 | 0 | if (fp == NULL) { |
771 | 0 | fp = fopen(".memorylist", "w"); |
772 | 0 | if (fp == NULL) |
773 | 0 | return; |
774 | 0 | } |
775 | | |
776 | | #ifdef MEM_LIST |
777 | | #if defined(HAVE_LOCALTIME) && defined(HAVE_STRFTIME) |
778 | | currentTime = time(NULL); |
779 | | tstruct = localtime(¤tTime); |
780 | | strftime(buf, sizeof(buf) - 1, "%I:%M:%S %p", tstruct); |
781 | | fprintf(fp," %s\n\n", buf); |
782 | | #endif |
783 | | |
784 | | |
785 | | fprintf(fp," MEMORY ALLOCATED : %lu, MAX was %lu\n", |
786 | | debugMemSize, debugMaxMemSize); |
787 | | fprintf(fp,"BLOCK NUMBER SIZE TYPE\n"); |
788 | | idx = 0; |
789 | | xmlMutexLock(xmlMemMutex); |
790 | | p = memlist; |
791 | | while (p) { |
792 | | fprintf(fp,"%-5u %6lu %6lu ",idx++,p->mh_number, |
793 | | (unsigned long)p->mh_size); |
794 | | switch (p->mh_type) { |
795 | | case STRDUP_TYPE:fprintf(fp,"strdup() in ");break; |
796 | | case MALLOC_TYPE:fprintf(fp,"malloc() in ");break; |
797 | | case REALLOC_TYPE:fprintf(fp,"realloc() in ");break; |
798 | | case MALLOC_ATOMIC_TYPE:fprintf(fp,"atomicmalloc() in ");break; |
799 | | case REALLOC_ATOMIC_TYPE:fprintf(fp,"atomicrealloc() in ");break; |
800 | | default: |
801 | | fprintf(fp,"Unknown memory block, may be corrupted"); |
802 | | xmlMutexUnlock(xmlMemMutex); |
803 | | if (old_fp == NULL) |
804 | | fclose(fp); |
805 | | return; |
806 | | } |
807 | | if (p->mh_file != NULL) fprintf(fp,"%s(%u)", p->mh_file, p->mh_line); |
808 | | if (p->mh_tag != MEMTAG) |
809 | | fprintf(fp," INVALID"); |
810 | | nb++; |
811 | | if (nb < 100) |
812 | | xmlMemContentShow(fp, p); |
813 | | else |
814 | | fprintf(fp," skip"); |
815 | | |
816 | | fprintf(fp,"\n"); |
817 | | p = p->mh_next; |
818 | | } |
819 | | xmlMutexUnlock(xmlMemMutex); |
820 | | #else |
821 | 0 | fprintf(fp,"Memory list not compiled (MEM_LIST not defined !)\n"); |
822 | 0 | #endif |
823 | 0 | if (old_fp == NULL) |
824 | 0 | fclose(fp); |
825 | 0 | } |
826 | | |
827 | | #ifdef MEM_LIST |
828 | | |
829 | | static void debugmem_list_add(MEMHDR *p) |
830 | | { |
831 | | p->mh_next = memlist; |
832 | | p->mh_prev = NULL; |
833 | | if (memlist) memlist->mh_prev = p; |
834 | | memlist = p; |
835 | | #ifdef MEM_LIST_DEBUG |
836 | | if (stderr) |
837 | | Mem_Display(stderr); |
838 | | #endif |
839 | | } |
840 | | |
841 | | static void debugmem_list_delete(MEMHDR *p) |
842 | | { |
843 | | if (p->mh_next) |
844 | | p->mh_next->mh_prev = p->mh_prev; |
845 | | if (p->mh_prev) |
846 | | p->mh_prev->mh_next = p->mh_next; |
847 | | else memlist = p->mh_next; |
848 | | #ifdef MEM_LIST_DEBUG |
849 | | if (stderr) |
850 | | Mem_Display(stderr); |
851 | | #endif |
852 | | } |
853 | | |
854 | | #endif |
855 | | |
856 | | /* |
857 | | * debugmem_tag_error: |
858 | | * |
859 | | * internal error function. |
860 | | */ |
861 | | |
862 | | static void debugmem_tag_error(void *p) |
863 | 0 | { |
864 | 0 | xmlGenericError(xmlGenericErrorContext, |
865 | 0 | "Memory tag error occurs :%p \n\t bye\n", p); |
866 | | #ifdef MEM_LIST |
867 | | if (stderr) |
868 | | xmlMemDisplay(stderr); |
869 | | #endif |
870 | 0 | } |
871 | | |
872 | | #ifdef MEM_LIST |
873 | | static FILE *xmlMemoryDumpFile = NULL; |
874 | | #endif |
875 | | |
876 | | /** |
877 | | * xmlMemShow: |
878 | | * @fp: a FILE descriptor used as the output file |
879 | | * @nr: number of entries to dump |
880 | | * |
881 | | * show a show display of the memory allocated, and dump |
882 | | * the @nr last allocated areas which were not freed |
883 | | */ |
884 | | |
885 | | void |
886 | | xmlMemShow(FILE *fp, int nr ATTRIBUTE_UNUSED) |
887 | 0 | { |
888 | | #ifdef MEM_LIST |
889 | | MEMHDR *p; |
890 | | #endif |
891 | |
|
892 | 0 | if (fp != NULL) |
893 | 0 | fprintf(fp," MEMORY ALLOCATED : %lu, MAX was %lu\n", |
894 | 0 | debugMemSize, debugMaxMemSize); |
895 | | #ifdef MEM_LIST |
896 | | xmlMutexLock(xmlMemMutex); |
897 | | if (nr > 0) { |
898 | | fprintf(fp,"NUMBER SIZE TYPE WHERE\n"); |
899 | | p = memlist; |
900 | | while ((p) && nr > 0) { |
901 | | fprintf(fp,"%6lu %6lu ",p->mh_number,(unsigned long)p->mh_size); |
902 | | switch (p->mh_type) { |
903 | | case STRDUP_TYPE:fprintf(fp,"strdup() in ");break; |
904 | | case MALLOC_TYPE:fprintf(fp,"malloc() in ");break; |
905 | | case MALLOC_ATOMIC_TYPE:fprintf(fp,"atomicmalloc() in ");break; |
906 | | case REALLOC_TYPE:fprintf(fp,"realloc() in ");break; |
907 | | case REALLOC_ATOMIC_TYPE:fprintf(fp,"atomicrealloc() in ");break; |
908 | | default:fprintf(fp," ??? in ");break; |
909 | | } |
910 | | if (p->mh_file != NULL) |
911 | | fprintf(fp,"%s(%u)", p->mh_file, p->mh_line); |
912 | | if (p->mh_tag != MEMTAG) |
913 | | fprintf(fp," INVALID"); |
914 | | xmlMemContentShow(fp, p); |
915 | | fprintf(fp,"\n"); |
916 | | nr--; |
917 | | p = p->mh_next; |
918 | | } |
919 | | } |
920 | | xmlMutexUnlock(xmlMemMutex); |
921 | | #endif /* MEM_LIST */ |
922 | 0 | } |
923 | | |
924 | | /** |
925 | | * xmlMemoryDump: |
926 | | * |
927 | | * Dump in-extenso the memory blocks allocated to the file .memorylist |
928 | | */ |
929 | | |
930 | | void |
931 | | xmlMemoryDump(void) |
932 | 0 | { |
933 | | #ifdef MEM_LIST |
934 | | FILE *dump; |
935 | | |
936 | | if (debugMaxMemSize == 0) |
937 | | return; |
938 | | dump = fopen(".memdump", "w"); |
939 | | if (dump == NULL) |
940 | | xmlMemoryDumpFile = stderr; |
941 | | else xmlMemoryDumpFile = dump; |
942 | | |
943 | | xmlMemDisplay(xmlMemoryDumpFile); |
944 | | |
945 | | if (dump != NULL) fclose(dump); |
946 | | #endif /* MEM_LIST */ |
947 | 0 | } |
948 | | |
949 | | |
950 | | /**************************************************************** |
951 | | * * |
952 | | * Initialization Routines * |
953 | | * * |
954 | | ****************************************************************/ |
955 | | |
956 | | /** |
957 | | * xmlInitMemory: |
958 | | * |
959 | | * Initialize the memory layer. |
960 | | * |
961 | | * Returns 0 on success |
962 | | */ |
963 | | int |
964 | | xmlInitMemory(void) |
965 | 14 | { |
966 | 14 | #ifdef HAVE_STDLIB_H |
967 | 14 | char *breakpoint; |
968 | 14 | #endif |
969 | | #ifdef DEBUG_MEMORY |
970 | | xmlGenericError(xmlGenericErrorContext, |
971 | | "xmlInitMemory()\n"); |
972 | | #endif |
973 | | /* |
974 | | This is really not good code (see Bug 130419). Suggestions for |
975 | | improvement will be welcome! |
976 | | */ |
977 | 14 | if (xmlMemInitialized) return(-1); |
978 | 14 | xmlMemInitialized = 1; |
979 | 14 | xmlMemMutex = xmlNewMutex(); |
980 | | |
981 | 14 | #ifdef HAVE_STDLIB_H |
982 | 14 | breakpoint = getenv("XML_MEM_BREAKPOINT"); |
983 | 14 | if (breakpoint != NULL) { |
984 | 0 | sscanf(breakpoint, "%ud", &xmlMemStopAtBlock); |
985 | 0 | } |
986 | 14 | #endif |
987 | 14 | #ifdef HAVE_STDLIB_H |
988 | 14 | breakpoint = getenv("XML_MEM_TRACE"); |
989 | 14 | if (breakpoint != NULL) { |
990 | 0 | sscanf(breakpoint, "%p", &xmlMemTraceBlockAt); |
991 | 0 | } |
992 | 14 | #endif |
993 | | |
994 | | #ifdef DEBUG_MEMORY |
995 | | xmlGenericError(xmlGenericErrorContext, |
996 | | "xmlInitMemory() Ok\n"); |
997 | | #endif |
998 | 14 | return(0); |
999 | 14 | } |
1000 | | |
1001 | | /** |
1002 | | * xmlCleanupMemory: |
1003 | | * |
1004 | | * Free up all the memory allocated by the library for its own |
1005 | | * use. This should not be called by user level code. |
1006 | | */ |
1007 | | void |
1008 | 0 | xmlCleanupMemory(void) { |
1009 | | #ifdef DEBUG_MEMORY |
1010 | | xmlGenericError(xmlGenericErrorContext, |
1011 | | "xmlCleanupMemory()\n"); |
1012 | | #endif |
1013 | 0 | if (xmlMemInitialized == 0) |
1014 | 0 | return; |
1015 | | |
1016 | 0 | xmlFreeMutex(xmlMemMutex); |
1017 | 0 | xmlMemMutex = NULL; |
1018 | 0 | xmlMemInitialized = 0; |
1019 | | #ifdef DEBUG_MEMORY |
1020 | | xmlGenericError(xmlGenericErrorContext, |
1021 | | "xmlCleanupMemory() Ok\n"); |
1022 | | #endif |
1023 | 0 | } |
1024 | | |
1025 | | /** |
1026 | | * xmlMemSetup: |
1027 | | * @freeFunc: the free() function to use |
1028 | | * @mallocFunc: the malloc() function to use |
1029 | | * @reallocFunc: the realloc() function to use |
1030 | | * @strdupFunc: the strdup() function to use |
1031 | | * |
1032 | | * Override the default memory access functions with a new set |
1033 | | * This has to be called before any other libxml routines ! |
1034 | | * |
1035 | | * Should this be blocked if there was already some allocations |
1036 | | * done ? |
1037 | | * |
1038 | | * Returns 0 on success |
1039 | | */ |
1040 | | int |
1041 | | xmlMemSetup(xmlFreeFunc freeFunc, xmlMallocFunc mallocFunc, |
1042 | 0 | xmlReallocFunc reallocFunc, xmlStrdupFunc strdupFunc) { |
1043 | | #ifdef DEBUG_MEMORY |
1044 | | xmlGenericError(xmlGenericErrorContext, |
1045 | | "xmlMemSetup()\n"); |
1046 | | #endif |
1047 | 0 | if (freeFunc == NULL) |
1048 | 0 | return(-1); |
1049 | 0 | if (mallocFunc == NULL) |
1050 | 0 | return(-1); |
1051 | 0 | if (reallocFunc == NULL) |
1052 | 0 | return(-1); |
1053 | 0 | if (strdupFunc == NULL) |
1054 | 0 | return(-1); |
1055 | 0 | xmlFree = freeFunc; |
1056 | 0 | xmlMalloc = mallocFunc; |
1057 | 0 | xmlMallocAtomic = mallocFunc; |
1058 | 0 | xmlRealloc = reallocFunc; |
1059 | 0 | xmlMemStrdup = strdupFunc; |
1060 | | #ifdef DEBUG_MEMORY |
1061 | | xmlGenericError(xmlGenericErrorContext, |
1062 | | "xmlMemSetup() Ok\n"); |
1063 | | #endif |
1064 | 0 | return(0); |
1065 | 0 | } |
1066 | | |
1067 | | /** |
1068 | | * xmlMemGet: |
1069 | | * @freeFunc: place to save the free() function in use |
1070 | | * @mallocFunc: place to save the malloc() function in use |
1071 | | * @reallocFunc: place to save the realloc() function in use |
1072 | | * @strdupFunc: place to save the strdup() function in use |
1073 | | * |
1074 | | * Provides the memory access functions set currently in use |
1075 | | * |
1076 | | * Returns 0 on success |
1077 | | */ |
1078 | | int |
1079 | | xmlMemGet(xmlFreeFunc *freeFunc, xmlMallocFunc *mallocFunc, |
1080 | 0 | xmlReallocFunc *reallocFunc, xmlStrdupFunc *strdupFunc) { |
1081 | 0 | if (freeFunc != NULL) *freeFunc = xmlFree; |
1082 | 0 | if (mallocFunc != NULL) *mallocFunc = xmlMalloc; |
1083 | 0 | if (reallocFunc != NULL) *reallocFunc = xmlRealloc; |
1084 | 0 | if (strdupFunc != NULL) *strdupFunc = xmlMemStrdup; |
1085 | 0 | return(0); |
1086 | 0 | } |
1087 | | |
1088 | | /** |
1089 | | * xmlGcMemSetup: |
1090 | | * @freeFunc: the free() function to use |
1091 | | * @mallocFunc: the malloc() function to use |
1092 | | * @mallocAtomicFunc: the malloc() function to use for atomic allocations |
1093 | | * @reallocFunc: the realloc() function to use |
1094 | | * @strdupFunc: the strdup() function to use |
1095 | | * |
1096 | | * Override the default memory access functions with a new set |
1097 | | * This has to be called before any other libxml routines ! |
1098 | | * The mallocAtomicFunc is specialized for atomic block |
1099 | | * allocations (i.e. of areas useful for garbage collected memory allocators |
1100 | | * |
1101 | | * Should this be blocked if there was already some allocations |
1102 | | * done ? |
1103 | | * |
1104 | | * Returns 0 on success |
1105 | | */ |
1106 | | int |
1107 | | xmlGcMemSetup(xmlFreeFunc freeFunc, xmlMallocFunc mallocFunc, |
1108 | | xmlMallocFunc mallocAtomicFunc, xmlReallocFunc reallocFunc, |
1109 | 0 | xmlStrdupFunc strdupFunc) { |
1110 | | #ifdef DEBUG_MEMORY |
1111 | | xmlGenericError(xmlGenericErrorContext, |
1112 | | "xmlGcMemSetup()\n"); |
1113 | | #endif |
1114 | 0 | if (freeFunc == NULL) |
1115 | 0 | return(-1); |
1116 | 0 | if (mallocFunc == NULL) |
1117 | 0 | return(-1); |
1118 | 0 | if (mallocAtomicFunc == NULL) |
1119 | 0 | return(-1); |
1120 | 0 | if (reallocFunc == NULL) |
1121 | 0 | return(-1); |
1122 | 0 | if (strdupFunc == NULL) |
1123 | 0 | return(-1); |
1124 | 0 | xmlFree = freeFunc; |
1125 | 0 | xmlMalloc = mallocFunc; |
1126 | 0 | xmlMallocAtomic = mallocAtomicFunc; |
1127 | 0 | xmlRealloc = reallocFunc; |
1128 | 0 | xmlMemStrdup = strdupFunc; |
1129 | | #ifdef DEBUG_MEMORY |
1130 | | xmlGenericError(xmlGenericErrorContext, |
1131 | | "xmlGcMemSetup() Ok\n"); |
1132 | | #endif |
1133 | 0 | return(0); |
1134 | 0 | } |
1135 | | |
1136 | | /** |
1137 | | * xmlGcMemGet: |
1138 | | * @freeFunc: place to save the free() function in use |
1139 | | * @mallocFunc: place to save the malloc() function in use |
1140 | | * @mallocAtomicFunc: place to save the atomic malloc() function in use |
1141 | | * @reallocFunc: place to save the realloc() function in use |
1142 | | * @strdupFunc: place to save the strdup() function in use |
1143 | | * |
1144 | | * Provides the memory access functions set currently in use |
1145 | | * The mallocAtomicFunc is specialized for atomic block |
1146 | | * allocations (i.e. of areas useful for garbage collected memory allocators |
1147 | | * |
1148 | | * Returns 0 on success |
1149 | | */ |
1150 | | int |
1151 | | xmlGcMemGet(xmlFreeFunc *freeFunc, xmlMallocFunc *mallocFunc, |
1152 | | xmlMallocFunc *mallocAtomicFunc, xmlReallocFunc *reallocFunc, |
1153 | 0 | xmlStrdupFunc *strdupFunc) { |
1154 | 0 | if (freeFunc != NULL) *freeFunc = xmlFree; |
1155 | 0 | if (mallocFunc != NULL) *mallocFunc = xmlMalloc; |
1156 | 0 | if (mallocAtomicFunc != NULL) *mallocAtomicFunc = xmlMallocAtomic; |
1157 | 0 | if (reallocFunc != NULL) *reallocFunc = xmlRealloc; |
1158 | 0 | if (strdupFunc != NULL) *strdupFunc = xmlMemStrdup; |
1159 | 0 | return(0); |
1160 | 0 | } |
1161 | | |
1162 | | #define bottom_xmlmemory |
1163 | | #include "elfgcchack.h" |