|
1 /* |
|
2 * libxml2_xmlmemory.c: libxml memory allocator wrapper. |
|
3 * |
|
4 * daniel@veillard.com |
|
5 * See Copyright for the status of this software. |
|
6 * Portion Copyright © 2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved. |
|
7 */ |
|
8 |
|
9 #define IN_LIBXML |
|
10 #include "xmlenglibxml.h" |
|
11 |
|
12 #include <string.h> |
|
13 |
|
14 #ifdef HAVE_SYS_TYPES_H |
|
15 #include <sys/types.h> |
|
16 #endif |
|
17 |
|
18 #ifdef HAVE_TIME_H |
|
19 #include <time.h> |
|
20 #endif |
|
21 |
|
22 #ifdef HAVE_STDLIB_H |
|
23 #include <stdlib.h> |
|
24 #else |
|
25 #ifdef HAVE_MALLOC_H |
|
26 #include <malloc.h> |
|
27 #endif |
|
28 #endif |
|
29 |
|
30 #ifdef HAVE_CTYPE_H |
|
31 #include <ctype.h> |
|
32 #endif |
|
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 <stdapis/libxml2/libxml2_globals.h> |
|
47 |
|
48 void xmlMallocBreakpoint(void); |
|
49 |
|
50 /************************************************************************ |
|
51 * * |
|
52 * Macros, variables and associated types * |
|
53 * * |
|
54 ************************************************************************/ |
|
55 |
|
56 |
|
57 /* |
|
58 * Each of the blocks allocated begin with a header containing information |
|
59 */ |
|
60 |
|
61 #define MEMTAG 0x5aa5 |
|
62 |
|
63 #define MALLOC_TYPE 1 |
|
64 #define REALLOC_TYPE 2 |
|
65 #define STRDUP_TYPE 3 |
|
66 #define MALLOC_ATOMIC_TYPE 4 |
|
67 #define REALLOC_ATOMIC_TYPE 5 |
|
68 |
|
69 typedef struct memnod { |
|
70 unsigned int mh_tag; |
|
71 unsigned int mh_type; |
|
72 unsigned long mh_number; |
|
73 size_t mh_size; |
|
74 #ifdef MEM_LIST |
|
75 struct memnod* mh_next; |
|
76 struct memnod* mh_prev; |
|
77 #endif |
|
78 const char* mh_file; |
|
79 unsigned int mh_line; |
|
80 } MEMHDR; |
|
81 |
|
82 |
|
83 #ifdef SUN4 |
|
84 #define ALIGN_SIZE 16 |
|
85 #else |
|
86 #define ALIGN_SIZE sizeof(double) |
|
87 #endif |
|
88 #define HDR_SIZE sizeof(MEMHDR) |
|
89 #define RESERVE_SIZE (((HDR_SIZE + (ALIGN_SIZE-1)) \ |
|
90 / ALIGN_SIZE ) * ALIGN_SIZE) |
|
91 |
|
92 |
|
93 #define CLIENT_2_HDR(a) ((MEMHDR*) (((char *) (a)) - RESERVE_SIZE)) |
|
94 #define HDR_2_CLIENT(a) ((void*) (((char *) (a)) + RESERVE_SIZE)) |
|
95 |
|
96 #ifdef MEM_LIST |
|
97 static MEMHDR *memlist = NULL; |
|
98 #endif |
|
99 |
|
100 static void debugmem_tag_error(void *addr); |
|
101 #ifdef MEM_LIST |
|
102 static void debugmem_list_add(MEMHDR*); |
|
103 static void debugmem_list_delete(MEMHDR*); |
|
104 #endif |
|
105 #define Mem_Tag_Err(a) debugmem_tag_error(a); |
|
106 |
|
107 #ifndef TEST_POINT |
|
108 #define TEST_POINT |
|
109 #endif |
|
110 |
|
111 /** |
|
112 * xmlMallocBreakpoint: |
|
113 * |
|
114 * Breakpoint to use in conjunction with xmlMemStopAtBlock. When the block |
|
115 * number reaches the specified value this function is called. One need to add a breakpoint |
|
116 * to it to get the context in which the given block is allocated. |
|
117 */ |
|
118 |
|
119 void |
|
120 xmlMallocBreakpoint(void) { |
|
121 LOAD_GS_DIRECT |
|
122 xmlGenericError(xmlGenericErrorContext, |
|
123 EMBED_ERRTXT("xmlMallocBreakpoint reached on block %d\n"), xmlMemStopAtBlock); |
|
124 } |
|
125 |
|
126 /** |
|
127 * xmlMallocLoc: |
|
128 * @param size an int specifying the size in byte to allocate. |
|
129 * @param file the file name or NULL |
|
130 * @param line the line number |
|
131 * |
|
132 * a malloc() equivalent, with logging of the allocation info. |
|
133 * |
|
134 * Returns a pointer to the allocated area or NULL in case of lack of memory. |
|
135 */ |
|
136 XMLPUBFUNEXPORT void* |
|
137 xmlMallocLoc(size_t size, const char * file, int line) |
|
138 { |
|
139 LOAD_GS_DIRECT |
|
140 MEMHDR *p; |
|
141 void *ret; |
|
142 |
|
143 if (!xmlMemInitialized) xmlInitMemory(); |
|
144 #ifdef DEBUG_MEMORY |
|
145 xmlGenericError(xmlGenericErrorContext, "Malloc(%d)\n",size); |
|
146 #endif |
|
147 |
|
148 TEST_POINT |
|
149 |
|
150 p = (MEMHDR *) malloc(RESERVE_SIZE+size); |
|
151 |
|
152 if (!p) { |
|
153 xmlGenericError(xmlGenericErrorContext, "xmlMallocLoc : Out of free space\n"); |
|
154 xmlMemoryDump(); |
|
155 return(NULL); |
|
156 } |
|
157 p->mh_tag = MEMTAG; |
|
158 p->mh_size = size; |
|
159 p->mh_type = MALLOC_TYPE; |
|
160 p->mh_file = file; |
|
161 p->mh_line = line; |
|
162 xmlMutexLock(xmlMemMutex); |
|
163 p->mh_number = ++g_block; |
|
164 debugMemSize += size; |
|
165 if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize; |
|
166 #ifdef MEM_LIST |
|
167 debugmem_list_add(p); |
|
168 #endif |
|
169 xmlMutexUnlock(xmlMemMutex); |
|
170 |
|
171 #ifdef DEBUG_MEMORY |
|
172 xmlGenericError(xmlGenericErrorContext, "Malloc(%d) Ok\n",size); |
|
173 #endif |
|
174 |
|
175 if (xmlMemStopAtBlock == p->mh_number) xmlMallocBreakpoint(); |
|
176 |
|
177 // agathe problem here |
|
178 ret = HDR_2_CLIENT(p); |
|
179 |
|
180 if (xmlMemTraceBlockAt == ret) { |
|
181 xmlGenericError(xmlGenericErrorContext, "%p : Malloc(%d) Ok\n", xmlMemTraceBlockAt, size); |
|
182 xmlMallocBreakpoint(); |
|
183 } |
|
184 |
|
185 TEST_POINT |
|
186 |
|
187 return(ret); |
|
188 } |
|
189 |
|
190 /** |
|
191 * xmlMallocAtomicLoc: |
|
192 * @param size an int specifying the size in byte to allocate. |
|
193 * @param file the file name or NULL |
|
194 * @param line the line number |
|
195 * |
|
196 * a malloc() equivalent, with logging of the allocation info. |
|
197 * |
|
198 * Returns a pointer to the allocated area or NULL in case of lack of memory. |
|
199 */ |
|
200 |
|
201 XMLPUBFUNEXPORT void * |
|
202 xmlMallocAtomicLoc(size_t size, const char * file, int line) |
|
203 { |
|
204 LOAD_GS_DIRECT |
|
205 MEMHDR *p; |
|
206 void *ret; |
|
207 |
|
208 if (!xmlMemInitialized) xmlInitMemory(); |
|
209 #ifdef DEBUG_MEMORY |
|
210 xmlGenericError(xmlGenericErrorContext, |
|
211 "Malloc(%d)\n",size); |
|
212 #endif |
|
213 |
|
214 TEST_POINT |
|
215 |
|
216 p = (MEMHDR *) malloc(RESERVE_SIZE+size); |
|
217 |
|
218 if (!p) { |
|
219 xmlGenericError(xmlGenericErrorContext, |
|
220 "xmlMallocLoc : Out of free space\n"); |
|
221 xmlMemoryDump(); |
|
222 return(NULL); |
|
223 } |
|
224 p->mh_tag = MEMTAG; |
|
225 p->mh_size = size; |
|
226 p->mh_type = MALLOC_ATOMIC_TYPE; |
|
227 p->mh_file = file; |
|
228 p->mh_line = line; |
|
229 xmlMutexLock(xmlMemMutex); |
|
230 p->mh_number = ++g_block; |
|
231 debugMemSize += size; |
|
232 if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize; |
|
233 #ifdef MEM_LIST |
|
234 debugmem_list_add(p); |
|
235 #endif |
|
236 xmlMutexUnlock(xmlMemMutex); |
|
237 |
|
238 #ifdef DEBUG_MEMORY |
|
239 xmlGenericError(xmlGenericErrorContext, |
|
240 "Malloc(%d) Ok\n",size); |
|
241 #endif |
|
242 |
|
243 if (xmlMemStopAtBlock == p->mh_number) xmlMallocBreakpoint(); |
|
244 |
|
245 ret = HDR_2_CLIENT(p); |
|
246 |
|
247 if (xmlMemTraceBlockAt == ret) { |
|
248 xmlGenericError(xmlGenericErrorContext, |
|
249 "%p : Malloc(%d) Ok\n", xmlMemTraceBlockAt, size); |
|
250 xmlMallocBreakpoint(); |
|
251 } |
|
252 |
|
253 TEST_POINT |
|
254 |
|
255 return(ret); |
|
256 } |
|
257 /** |
|
258 * xmlMemMalloc: |
|
259 * @param size an int specifying the size in byte to allocate. |
|
260 * |
|
261 * a malloc() equivalent, with logging of the allocation info. |
|
262 * |
|
263 * Returns a pointer to the allocated area or NULL in case of lack of memory. |
|
264 */ |
|
265 |
|
266 XMLPUBFUNEXPORT void * |
|
267 xmlMemMalloc(size_t size) |
|
268 { |
|
269 return(xmlMallocLoc(size, "none", 0)); |
|
270 } |
|
271 |
|
272 /** |
|
273 * xmlReallocLoc: |
|
274 * @param ptr the initial memory block pointer |
|
275 * @param size an int specifying the size in byte to allocate. |
|
276 * @param file the file name or NULL |
|
277 * @param line the line number |
|
278 * |
|
279 * a realloc() equivalent, with logging of the allocation info. |
|
280 * |
|
281 * Returns a pointer to the allocated area or NULL in case of lack of memory. |
|
282 */ |
|
283 |
|
284 XMLPUBFUNEXPORT void * |
|
285 xmlReallocLoc(void *ptr,size_t size, const char * file, int line) |
|
286 { |
|
287 LOAD_GS_DIRECT |
|
288 MEMHDR *p; |
|
289 unsigned long number; |
|
290 |
|
291 if (ptr == NULL) |
|
292 return(xmlMallocLoc(size, file, line)); |
|
293 |
|
294 if (!xmlMemInitialized) xmlInitMemory(); |
|
295 TEST_POINT |
|
296 |
|
297 p = CLIENT_2_HDR(ptr); |
|
298 number = p->mh_number; |
|
299 if (p->mh_tag != MEMTAG) { |
|
300 Mem_Tag_Err(p); |
|
301 goto error; |
|
302 } |
|
303 p->mh_tag = ~MEMTAG; |
|
304 xmlMutexLock(xmlMemMutex); |
|
305 debugMemSize -= p->mh_size; |
|
306 #ifdef MEM_LIST |
|
307 debugmem_list_delete(p); |
|
308 #endif |
|
309 xmlMutexUnlock(xmlMemMutex); |
|
310 |
|
311 p = (MEMHDR *) realloc(p,RESERVE_SIZE+size); |
|
312 if (!p) { |
|
313 goto error; |
|
314 } |
|
315 if (xmlMemTraceBlockAt == ptr) { |
|
316 xmlGenericError(xmlGenericErrorContext, |
|
317 EMBED_ERRTXT("%p : Realloced(%d -> %d) Ok\n"), |
|
318 xmlMemTraceBlockAt, p->mh_size, size); |
|
319 xmlMallocBreakpoint(); |
|
320 } |
|
321 p->mh_tag = MEMTAG; |
|
322 p->mh_number = number; |
|
323 p->mh_type = REALLOC_TYPE; |
|
324 p->mh_size = size; |
|
325 p->mh_file = file; |
|
326 p->mh_line = line; |
|
327 xmlMutexLock(xmlMemMutex); |
|
328 debugMemSize += size; |
|
329 if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize; |
|
330 #ifdef MEM_LIST |
|
331 debugmem_list_add(p); |
|
332 #endif |
|
333 xmlMutexUnlock(xmlMemMutex); |
|
334 |
|
335 TEST_POINT |
|
336 |
|
337 return(HDR_2_CLIENT(p)); |
|
338 |
|
339 error: |
|
340 return(NULL); |
|
341 } |
|
342 |
|
343 /** |
|
344 * xmlMemRealloc: |
|
345 * @param ptr the initial memory block pointer |
|
346 * @param size an int specifying the size in byte to allocate. |
|
347 * |
|
348 * a realloc() equivalent, with logging of the allocation info. |
|
349 * |
|
350 * Returns a pointer to the allocated area or NULL in case of lack of memory. |
|
351 */ |
|
352 XMLPUBFUNEXPORT void * |
|
353 xmlMemRealloc(void *ptr,size_t size) { |
|
354 return(xmlReallocLoc(ptr, size, "none", 0)); |
|
355 } |
|
356 |
|
357 /** |
|
358 * xmlMemFree: |
|
359 * @param ptr the memory block pointer |
|
360 * |
|
361 * a free() equivalent, with error checking. |
|
362 */ |
|
363 XMLPUBFUNEXPORT void |
|
364 xmlMemFree(void *ptr) |
|
365 { |
|
366 LOAD_GS_DIRECT |
|
367 MEMHDR *p; |
|
368 char *target; |
|
369 |
|
370 if (ptr == (void *) -1) { |
|
371 xmlGenericError(xmlGenericErrorContext, |
|
372 EMBED_ERRTXT("trying to free pointer from freed area\n")); |
|
373 goto error; |
|
374 } |
|
375 |
|
376 if (xmlMemTraceBlockAt == ptr) { |
|
377 xmlGenericError(xmlGenericErrorContext, |
|
378 EMBED_ERRTXT("%p : Freed()\n"), xmlMemTraceBlockAt); |
|
379 xmlMallocBreakpoint(); |
|
380 } |
|
381 |
|
382 TEST_POINT |
|
383 |
|
384 target = (char *) ptr; |
|
385 |
|
386 p = CLIENT_2_HDR(ptr); |
|
387 if (p->mh_tag != MEMTAG) { |
|
388 Mem_Tag_Err(p); |
|
389 goto error; |
|
390 } |
|
391 p->mh_tag = ~MEMTAG; |
|
392 memset(target, -1, p->mh_size); |
|
393 xmlMutexLock(xmlMemMutex); |
|
394 debugMemSize -= p->mh_size; |
|
395 #ifdef MEM_LIST |
|
396 debugmem_list_delete(p); |
|
397 #endif |
|
398 xmlMutexUnlock(xmlMemMutex); |
|
399 |
|
400 free(p); |
|
401 |
|
402 TEST_POINT |
|
403 |
|
404 return; |
|
405 |
|
406 error: |
|
407 xmlGenericError(xmlGenericErrorContext, |
|
408 EMBED_ERRTXT("xmlMemFree(%lX) error\n"), (unsigned long) ptr); |
|
409 xmlMallocBreakpoint(); |
|
410 return; |
|
411 } |
|
412 |
|
413 /** |
|
414 * xmlMemStrdupLoc: |
|
415 * @param str the initial string pointer |
|
416 * @param file the file name or NULL |
|
417 * @param line the line number |
|
418 * |
|
419 * a strdup() equivalent, with logging of the allocation info. |
|
420 * |
|
421 * Returns a pointer to the new string or NULL if allocation error occurred. |
|
422 */ |
|
423 |
|
424 XMLPUBFUNEXPORT char * |
|
425 xmlMemStrdupLoc(const char *str, const char *file, int line) |
|
426 { |
|
427 LOAD_GS_DIRECT |
|
428 char *s; |
|
429 size_t size = strlen(str) + 1; |
|
430 MEMHDR *p; |
|
431 |
|
432 if (!xmlMemInitialized) xmlInitMemory(); |
|
433 TEST_POINT |
|
434 |
|
435 p = (MEMHDR *) malloc(RESERVE_SIZE+size); |
|
436 if (!p) { |
|
437 goto error; |
|
438 } |
|
439 p->mh_tag = MEMTAG; |
|
440 p->mh_size = size; |
|
441 p->mh_type = STRDUP_TYPE; |
|
442 p->mh_file = file; |
|
443 p->mh_line = line; |
|
444 xmlMutexLock(xmlMemMutex); |
|
445 p->mh_number = ++g_block; |
|
446 debugMemSize += size; |
|
447 if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize; |
|
448 #ifdef MEM_LIST |
|
449 debugmem_list_add(p); |
|
450 #endif |
|
451 xmlMutexUnlock(xmlMemMutex); |
|
452 |
|
453 s = (char *) HDR_2_CLIENT(p); |
|
454 |
|
455 if (xmlMemStopAtBlock == p->mh_number) xmlMallocBreakpoint(); |
|
456 |
|
457 if (s != NULL) |
|
458 strcpy(s,str); |
|
459 else |
|
460 goto error; |
|
461 |
|
462 TEST_POINT |
|
463 |
|
464 if (xmlMemTraceBlockAt == s) { |
|
465 xmlGenericError(xmlGenericErrorContext, |
|
466 EMBED_ERRTXT("%p : Strdup() Ok\n"), xmlMemTraceBlockAt); |
|
467 xmlMallocBreakpoint(); |
|
468 } |
|
469 |
|
470 return(s); |
|
471 |
|
472 error: |
|
473 return(NULL); |
|
474 } |
|
475 |
|
476 /** |
|
477 * xmlMemoryStrdup: |
|
478 * @param str the initial string pointer |
|
479 * |
|
480 * a strdup() equivalent, with logging of the allocation info. |
|
481 * |
|
482 * Returns a pointer to the new string or NULL if allocation error occurred. |
|
483 */ |
|
484 XMLPUBFUNEXPORT char * |
|
485 xmlMemoryStrdup(const char *str) { |
|
486 return(xmlMemStrdupLoc(str, "none", 0)); |
|
487 } |
|
488 |
|
489 /** |
|
490 * xmlMemUsed: |
|
491 * |
|
492 * Provides the amount of memory currently allocated |
|
493 * |
|
494 * Returns an int representing the amount of memory allocated. |
|
495 */ |
|
496 |
|
497 XMLPUBFUNEXPORT int |
|
498 xmlMemUsed(void) { |
|
499 LOAD_GS_DIRECT |
|
500 return(debugMemSize); |
|
501 } |
|
502 |
|
503 #ifdef MEM_LIST |
|
504 /** |
|
505 * xmlMemContentShow: |
|
506 * @param fp a FILE descriptor used as the output file |
|
507 * @param p a memory block header |
|
508 * |
|
509 * tries to show some content from the memory block |
|
510 */ |
|
511 |
|
512 static void |
|
513 xmlMemContentShow(FILE *fp, MEMHDR *p) |
|
514 { |
|
515 int i,j,len = p->mh_size; |
|
516 const char *buf = (const char *) HDR_2_CLIENT(p); |
|
517 |
|
518 if (p == NULL) { |
|
519 fprintf(fp, " NULL"); |
|
520 return; |
|
521 } |
|
522 |
|
523 for (i = 0;i < len;i++) { |
|
524 if (buf[i] == 0) break; |
|
525 if (!isprint((unsigned char) buf[i])) break; |
|
526 } |
|
527 if ((i < 4) && ((buf[i] != 0) || (i == 0))) { |
|
528 if (len >= 4) { |
|
529 MEMHDR *q; |
|
530 void *cur; |
|
531 |
|
532 for (j = 0;j < len -3;j += 4) { |
|
533 cur = *((void **) &buf[j]); |
|
534 q = CLIENT_2_HDR(cur); |
|
535 p = memlist; |
|
536 while (p != NULL) { |
|
537 if (p == q) break; |
|
538 p = p->mh_next; |
|
539 } |
|
540 if ((p != NULL) && (p == q)) { |
|
541 fprintf(fp, " pointer to #%lu at index %d", |
|
542 p->mh_number, j); |
|
543 return; |
|
544 } |
|
545 } |
|
546 } |
|
547 } else if ((i == 0) && (buf[i] == 0)) { |
|
548 fprintf(fp," null"); |
|
549 } else { |
|
550 if (buf[i] == 0) fprintf(fp," \"%.25s\"", buf); |
|
551 else { |
|
552 fprintf(fp," ["); |
|
553 for (j = 0;j < i;j++) |
|
554 fprintf(fp,"%c", buf[j]); |
|
555 fprintf(fp,"]"); |
|
556 } |
|
557 } |
|
558 } |
|
559 #endif |
|
560 |
|
561 #ifndef XMLENGINE_EXCLUDE_FILE_FUNC |
|
562 /** |
|
563 * xmlMemDisplay: |
|
564 * @param fp a FILE descriptor used as the output file, if NULL, the result is |
|
565 * written to the file .memorylist |
|
566 * |
|
567 * show in-extenso the memory blocks allocated |
|
568 */ |
|
569 void |
|
570 xmlMemDisplay(FILE *fp) |
|
571 { |
|
572 #ifdef MEM_LIST |
|
573 MEMHDR *p; |
|
574 unsigned idx; |
|
575 int nb = 0; |
|
576 #if defined(HAVE_LOCALTIME) && defined(HAVE_STRFTIME) |
|
577 time_t currentTime; |
|
578 char buf[500]; |
|
579 struct tm * tstruct; |
|
580 |
|
581 currentTime = time(NULL); |
|
582 tstruct = localtime(¤tTime); |
|
583 strftime(buf, sizeof(buf) - 1, "%I:%M:%S %p", tstruct); |
|
584 fprintf(fp," %s\n\n", buf); |
|
585 #endif |
|
586 |
|
587 |
|
588 fprintf(fp," MEMORY ALLOCATED : %lu, MAX was %lu\n", |
|
589 debugMemSize, debugMaxMemSize); |
|
590 fprintf(fp,"BLOCK NUMBER SIZE TYPE\n"); |
|
591 idx = 0; |
|
592 xmlMutexLock(xmlMemMutex); |
|
593 p = memlist; |
|
594 while (p) { |
|
595 fprintf(fp,"%-5u %6lu %6lu ",idx++,p->mh_number, |
|
596 (unsigned long)p->mh_size); |
|
597 switch (p->mh_type) { |
|
598 case STRDUP_TYPE:fprintf(fp,"strdup() in ");break; |
|
599 case MALLOC_TYPE:fprintf(fp,"malloc() in ");break; |
|
600 case REALLOC_TYPE:fprintf(fp,"realloc() in ");break; |
|
601 case MALLOC_ATOMIC_TYPE:fprintf(fp,"atomicmalloc() in ");break; |
|
602 case REALLOC_ATOMIC_TYPE:fprintf(fp,"atomicrealloc() in ");break; |
|
603 default:fprintf(fp," ??? in ");break; |
|
604 } |
|
605 if (p->mh_file != NULL) fprintf(fp,"%s(%d)", p->mh_file, p->mh_line); |
|
606 if (p->mh_tag != MEMTAG) |
|
607 fprintf(fp," INVALID"); |
|
608 nb++; |
|
609 if (nb < 100) |
|
610 xmlMemContentShow(fp, p); |
|
611 else |
|
612 fprintf(fp," skip"); |
|
613 |
|
614 fprintf(fp,"\n"); |
|
615 p = p->mh_next; |
|
616 } |
|
617 xmlMutexUnlock(xmlMemMutex); |
|
618 #else |
|
619 fprintf(fp,EMBED_ERRTXT("Memory list not compiled (MEM_LIST not defined !)\n")); |
|
620 #endif |
|
621 } |
|
622 #endif /* XMLENGINE_EXCLUDE_FILE_FUNC */ |
|
623 |
|
624 #ifdef MEM_LIST |
|
625 |
|
626 static void debugmem_list_add(MEMHDR *p) |
|
627 { |
|
628 p->mh_next = memlist; |
|
629 p->mh_prev = NULL; |
|
630 if (memlist) memlist->mh_prev = p; |
|
631 memlist = p; |
|
632 #ifdef MEM_LIST_DEBUG |
|
633 if (stderr) |
|
634 Mem_Display(stderr); |
|
635 #endif |
|
636 } |
|
637 |
|
638 static void debugmem_list_delete(MEMHDR *p) |
|
639 { |
|
640 if (p->mh_next) |
|
641 p->mh_next->mh_prev = p->mh_prev; |
|
642 if (p->mh_prev) |
|
643 p->mh_prev->mh_next = p->mh_next; |
|
644 else memlist = p->mh_next; |
|
645 #ifdef MEM_LIST_DEBUG |
|
646 if (stderr) |
|
647 Mem_Display(stderr); |
|
648 #endif |
|
649 } |
|
650 |
|
651 #endif |
|
652 |
|
653 /* |
|
654 * debugmem_tag_error: |
|
655 * |
|
656 * internal error function. |
|
657 */ |
|
658 |
|
659 static void debugmem_tag_error(void *p) |
|
660 { |
|
661 xmlGenericError(xmlGenericErrorContext, |
|
662 EMBED_ERRTXT("Memory tag error occurs :%p \n\t bye\n"), p); |
|
663 #ifdef MEM_LIST |
|
664 if (stderr) |
|
665 xmlMemDisplay(stderr); |
|
666 #endif |
|
667 } |
|
668 |
|
669 #ifdef MEM_LIST |
|
670 static FILE *xmlMemoryDumpFile = NULL; |
|
671 #endif |
|
672 |
|
673 #ifndef XMLENGINE_EXCLUDE_FILE_FUNC |
|
674 /** |
|
675 * xmlMemShow: |
|
676 * @param fp a FILE descriptor used as the output file |
|
677 * @param nr number of entries to dump |
|
678 * |
|
679 * show a show display of the memory allocated, and dump |
|
680 * the nr last allocated areas which were not freed |
|
681 */ |
|
682 void |
|
683 xmlMemShow(FILE *fp, int nr ATTRIBUTE_UNUSED) |
|
684 { |
|
685 #ifdef MEM_LIST |
|
686 MEMHDR *p; |
|
687 #endif |
|
688 |
|
689 if (fp != NULL) |
|
690 fprintf(fp,EMBED_ERRTXT(" MEMORY ALLOCATED : %lu, MAX was %lu\n"), |
|
691 debugMemSize, debugMaxMemSize); |
|
692 #ifdef MEM_LIST |
|
693 xmlMutexLock(xmlMemMutex); |
|
694 if (nr > 0) { |
|
695 fprintf(fp,"NUMBER SIZE TYPE WHERE\n"); |
|
696 p = memlist; |
|
697 while ((p) && nr > 0) { |
|
698 fprintf(fp,"%6lu %6lu ",p->mh_number,(unsigned long)p->mh_size); |
|
699 switch (p->mh_type) { |
|
700 case STRDUP_TYPE:fprintf(fp,"strdup() in ");break; |
|
701 case MALLOC_TYPE:fprintf(fp,"malloc() in ");break; |
|
702 case MALLOC_ATOMIC_TYPE:fprintf(fp,"atomicmalloc() in ");break; |
|
703 case REALLOC_TYPE:fprintf(fp,"realloc() in ");break; |
|
704 case REALLOC_ATOMIC_TYPE:fprintf(fp,"atomicrealloc() in ");break; |
|
705 default:fprintf(fp," ??? in ");break; |
|
706 } |
|
707 if (p->mh_file != NULL) |
|
708 fprintf(fp,"%s(%d)", p->mh_file, p->mh_line); |
|
709 if (p->mh_tag != MEMTAG) |
|
710 fprintf(fp," INVALID"); |
|
711 xmlMemContentShow(fp, p); |
|
712 fprintf(fp,"\n"); |
|
713 nr--; |
|
714 p = p->mh_next; |
|
715 } |
|
716 } |
|
717 xmlMutexUnlock(xmlMemMutex); |
|
718 #endif /* MEM_LIST */ |
|
719 } |
|
720 #endif /* XMLENGINE_EXCLUDE_FILE_FUNC */ |
|
721 |
|
722 /** |
|
723 * xmlMemoryDump: |
|
724 * |
|
725 * Dump in-extenso the memory blocks allocated to the file .memorylist |
|
726 */ |
|
727 |
|
728 XMLPUBFUNEXPORT void |
|
729 xmlMemoryDump(void) |
|
730 { |
|
731 #ifdef MEM_LIST |
|
732 FILE *dump; |
|
733 |
|
734 if (debugMaxMemSize == 0) |
|
735 return; |
|
736 dump = fopen(".memdump", "w"); |
|
737 if (dump == NULL) |
|
738 xmlMemoryDumpFile = stderr; |
|
739 else xmlMemoryDumpFile = dump; |
|
740 |
|
741 xmlMemDisplay(xmlMemoryDumpFile); |
|
742 |
|
743 if (dump != NULL) fclose(dump); |
|
744 #endif /* MEM_LIST */ |
|
745 } |
|
746 |
|
747 |
|
748 /**************************************************************** |
|
749 * * |
|
750 * Initialization Routines * |
|
751 * * |
|
752 ****************************************************************/ |
|
753 |
|
754 /** |
|
755 * xmlInitMemory: |
|
756 * |
|
757 * Initialize the memory layer. |
|
758 * |
|
759 * Returns 0 on success |
|
760 * |
|
761 * OOM: maybe possible -- during calls to standard library (???) |
|
762 */ |
|
763 XMLPUBFUNEXPORT int |
|
764 xmlInitMemory(void) |
|
765 { |
|
766 #ifdef DEBUG_MEMORY |
|
767 xmlGenericError(xmlGenericErrorContext, "xmlInitMemory() Ok\n"); |
|
768 #endif |
|
769 return(0); |
|
770 } |
|
771 |
|
772 /** |
|
773 * xmlCleanupMemory: |
|
774 * |
|
775 * Free up all the memory associated with memorys |
|
776 * |
|
777 * OOM: never |
|
778 */ |
|
779 XMLPUBFUNEXPORT void |
|
780 xmlCleanupMemory(void) { |
|
781 LOAD_GS_DIRECT |
|
782 if (xmlMemInitialized == 0) |
|
783 return; |
|
784 |
|
785 xmlFreeMutex(xmlMemMutex); |
|
786 xmlMemInitialized = 0; |
|
787 } |
|
788 |