diff --git a/ChangeLog b/ChangeLog index ffe14b24..0a970a75 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +Wed Jul 30 14:55:54 CEST 2008 Daniel Veillard + + * include/libxml/xmlmemory.h xmlmemory.c: add xmlMemDisplayLast to + help debug incremental memory leaks, and some cleanups + * runxmlconf.c: use that new call and avoid ever touching the + system catalog in the regression tests + Wed Jul 30 14:33:33 CEST 2008 Daniel Veillard * parser.c include/libxml/xmlerror.h: an XML-1.0 document can't load diff --git a/include/libxml/xmlmemory.h b/include/libxml/xmlmemory.h index 235721ce..ee8328ab 100644 --- a/include/libxml/xmlmemory.h +++ b/include/libxml/xmlmemory.h @@ -20,7 +20,7 @@ * * DEBUG_MEMORY replaces the allocator with a collect and debug * shell to the libc allocator. - * DEBUG_MEMORY should only be activated when debugging + * DEBUG_MEMORY should only be activated when debugging * libxml i.e. if libxml has been configured with --with-debug-mem too. */ /* #define DEBUG_MEMORY_FREED */ @@ -35,7 +35,7 @@ /** * DEBUG_MEMORY_LOCATION: * - * DEBUG_MEMORY_LOCATION should be activated only when debugging + * DEBUG_MEMORY_LOCATION should be activated only when debugging * libxml i.e. if libxml has been configured with --with-debug-mem too. */ #ifdef DEBUG_MEMORY_LOCATION @@ -105,18 +105,18 @@ XMLPUBFUN int XMLCALL xmlMallocFunc mallocFunc, xmlReallocFunc reallocFunc, xmlStrdupFunc strdupFunc); -XMLPUBFUN int XMLCALL +XMLPUBFUN int XMLCALL xmlMemGet (xmlFreeFunc *freeFunc, xmlMallocFunc *mallocFunc, xmlReallocFunc *reallocFunc, xmlStrdupFunc *strdupFunc); -XMLPUBFUN int XMLCALL +XMLPUBFUN int XMLCALL xmlGcMemSetup (xmlFreeFunc freeFunc, xmlMallocFunc mallocFunc, xmlMallocFunc mallocAtomicFunc, xmlReallocFunc reallocFunc, xmlStrdupFunc strdupFunc); -XMLPUBFUN int XMLCALL +XMLPUBFUN int XMLCALL xmlGcMemGet (xmlFreeFunc *freeFunc, xmlMallocFunc *mallocFunc, xmlMallocFunc *mallocAtomicFunc, @@ -126,42 +126,44 @@ XMLPUBFUN int XMLCALL /* * Initialization of the memory layer. */ -XMLPUBFUN int XMLCALL +XMLPUBFUN int XMLCALL xmlInitMemory (void); -/* +/* * Cleanup of the memory layer. */ -XMLPUBFUN void XMLCALL +XMLPUBFUN void XMLCALL xmlCleanupMemory (void); /* * These are specific to the XML debug memory wrapper. */ -XMLPUBFUN int XMLCALL +XMLPUBFUN int XMLCALL xmlMemUsed (void); -XMLPUBFUN int XMLCALL +XMLPUBFUN int XMLCALL xmlMemBlocks (void); -XMLPUBFUN void XMLCALL +XMLPUBFUN void XMLCALL xmlMemDisplay (FILE *fp); -XMLPUBFUN void XMLCALL +XMLPUBFUN void XMLCALL + xmlMemDisplayLast(FILE *fp, long nbBytes); +XMLPUBFUN void XMLCALL xmlMemShow (FILE *fp, int nr); -XMLPUBFUN void XMLCALL +XMLPUBFUN void XMLCALL xmlMemoryDump (void); -XMLPUBFUN void * XMLCALL +XMLPUBFUN void * XMLCALL xmlMemMalloc (size_t size); -XMLPUBFUN void * XMLCALL +XMLPUBFUN void * XMLCALL xmlMemRealloc (void *ptr,size_t size); -XMLPUBFUN void XMLCALL +XMLPUBFUN void XMLCALL xmlMemFree (void *ptr); -XMLPUBFUN char * XMLCALL +XMLPUBFUN char * XMLCALL xmlMemoryStrdup (const char *str); -XMLPUBFUN void * XMLCALL +XMLPUBFUN void * XMLCALL xmlMallocLoc (size_t size, const char *file, int line); -XMLPUBFUN void * XMLCALL +XMLPUBFUN void * XMLCALL xmlReallocLoc (void *ptr, size_t size, const char *file, int line); -XMLPUBFUN void * XMLCALL +XMLPUBFUN void * XMLCALL xmlMallocAtomicLoc (size_t size, const char *file, int line); -XMLPUBFUN char * XMLCALL +XMLPUBFUN char * XMLCALL xmlMemStrdupLoc (const char *str, const char *file, int line); diff --git a/runxmlconf.c b/runxmlconf.c index 0f0e54fb..f0f11580 100644 --- a/runxmlconf.c +++ b/runxmlconf.c @@ -125,38 +125,14 @@ static int addEntity(char *name, char *content) { /* * We need to trap calls to the resolver to not account memory for the catalog - * which is shared to the current running test. We also don't want to have - * network downloads modifying tests. + * and not rely on any external resources. */ static xmlParserInputPtr testExternalEntityLoader(const char *URL, const char *ID, xmlParserCtxtPtr ctxt) { xmlParserInputPtr ret; - int i; - for (i = 0;i < nb_entities;i++) { - if (!strcmp(testEntitiesName[i], URL)) { - ret = xmlNewStringInputStream(ctxt, - (const xmlChar *) testEntitiesValue[i]); - if (ret != NULL) { - ret->filename = (const char *) - xmlStrdup((xmlChar *)testEntitiesName[i]); - } - return(ret); - } - } - if (checkTestFile(URL)) { - ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt); - } else { - int memused = xmlMemUsed(); - ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt); - extraMemoryFromResolver += xmlMemUsed() - memused; - } -#if 0 - if (ret == NULL) { - fprintf(stderr, "Failed to find resource %s\n", URL); - } -#endif + ret = xmlNewInputFromFile(ctxt, (const char *) URL); return(ret); } @@ -377,6 +353,7 @@ xmlconfTestItem(xmlDocPtr doc, xmlNodePtr cur) { test_log("test %s : %s leaked %d bytes\n", id, filename, final - mem); nb_leaks++; + xmlMemDisplayLast(logfile, final - mem); } nb_tests++; diff --git a/xmlmemory.c b/xmlmemory.c index f9019a42..510d4ce8 100644 --- a/xmlmemory.c +++ b/xmlmemory.c @@ -34,7 +34,7 @@ /** * MEM_LIST: * - * keep track of all allocated blocks for error reporting + * keep track of all allocated blocks for error reporting * Always build the memory list ! */ #ifdef DEBUG_MEMORY_LOCATION @@ -162,7 +162,7 @@ xmlMallocLoc(size_t size, const char * file, int line) { MEMHDR *p; void *ret; - + if (!xmlMemInitialized) xmlInitMemory(); #ifdef DEBUG_MEMORY xmlGenericError(xmlGenericErrorContext, @@ -170,7 +170,7 @@ xmlMallocLoc(size_t size, const char * file, int line) #endif TEST_POINT - + p = (MEMHDR *) malloc(RESERVE_SIZE+size); if (!p) { @@ -178,7 +178,7 @@ xmlMallocLoc(size_t size, const char * file, int line) "xmlMallocLoc : Out of free space\n"); xmlMemoryDump(); return(NULL); - } + } p->mh_tag = MEMTAG; p->mh_size = size; p->mh_type = MALLOC_TYPE; @@ -193,12 +193,12 @@ xmlMallocLoc(size_t size, const char * file, int line) debugmem_list_add(p); #endif xmlMutexUnlock(xmlMemMutex); - + #ifdef DEBUG_MEMORY xmlGenericError(xmlGenericErrorContext, "Malloc(%d) Ok\n",size); #endif - + if (xmlMemStopAtBlock == p->mh_number) xmlMallocBreakpoint(); ret = HDR_2_CLIENT(p); @@ -230,7 +230,7 @@ xmlMallocAtomicLoc(size_t size, const char * file, int line) { MEMHDR *p; void *ret; - + if (!xmlMemInitialized) xmlInitMemory(); #ifdef DEBUG_MEMORY xmlGenericError(xmlGenericErrorContext, @@ -238,7 +238,7 @@ xmlMallocAtomicLoc(size_t size, const char * file, int line) #endif TEST_POINT - + p = (MEMHDR *) malloc(RESERVE_SIZE+size); if (!p) { @@ -246,7 +246,7 @@ xmlMallocAtomicLoc(size_t size, const char * file, int line) "xmlMallocLoc : Out of free space\n"); xmlMemoryDump(); return(NULL); - } + } p->mh_tag = MEMTAG; p->mh_size = size; p->mh_type = MALLOC_ATOMIC_TYPE; @@ -266,7 +266,7 @@ xmlMallocAtomicLoc(size_t size, const char * file, int line) xmlGenericError(xmlGenericErrorContext, "Malloc(%d) Ok\n",size); #endif - + if (xmlMemStopAtBlock == p->mh_number) xmlMallocBreakpoint(); ret = HDR_2_CLIENT(p); @@ -341,7 +341,7 @@ xmlReallocLoc(void *ptr,size_t size, const char * file, int line) debugmem_list_delete(p); #endif xmlMutexUnlock(xmlMemMutex); - + p = (MEMHDR *) realloc(p,RESERVE_SIZE+size); if (!p) { goto error; @@ -374,8 +374,8 @@ xmlReallocLoc(void *ptr,size_t size, const char * file, int line) "Realloced(%d to %d) Ok\n", oldsize, size); #endif return(HDR_2_CLIENT(p)); - -error: + +error: return(NULL); } @@ -455,10 +455,10 @@ xmlMemFree(void *ptr) xmlGenericError(xmlGenericErrorContext, "Freed(%d) Ok\n", size); #endif - + return; - -error: + +error: xmlGenericError(xmlGenericErrorContext, "xmlMemFree(%lX) error\n", (unsigned long) ptr); xmlMallocBreakpoint(); @@ -504,16 +504,16 @@ xmlMemStrdupLoc(const char *str, const char *file, int line) debugmem_list_add(p); #endif xmlMutexUnlock(xmlMemMutex); - + s = (char *) HDR_2_CLIENT(p); - + if (xmlMemStopAtBlock == p->mh_number) xmlMallocBreakpoint(); if (s != NULL) strcpy(s,str); else goto error; - + TEST_POINT if (xmlMemTraceBlockAt == s) { @@ -617,7 +617,7 @@ xmlMemContentShow(FILE *fp, MEMHDR *p) } else if ((i == 0) && (buf[i] == 0)) { fprintf(fp," null"); } else { - if (buf[i] == 0) fprintf(fp," \"%.25s\"", buf); + if (buf[i] == 0) fprintf(fp," \"%.25s\"", buf); else { fprintf(fp," ["); for (j = 0;j < i;j++) @@ -628,6 +628,79 @@ xmlMemContentShow(FILE *fp, MEMHDR *p) } #endif +/** + * xmlMemDisplayLast: + * @fp: a FILE descriptor used as the output file, if NULL, the result is + * written to the file .memorylist + * @nbBytes: the amount of memory to dump + * + * the last nbBytes of memory allocated and not freed, useful for dumping + * the memory left allocated between two places at runtime. + */ + +void +xmlMemDisplayLast(FILE *fp, long nbBytes) +{ +#ifdef MEM_LIST + MEMHDR *p; + unsigned idx; + int nb = 0; +#endif + FILE *old_fp = fp; + + if (nbBytes <= 0) + return; + + if (fp == NULL) { + fp = fopen(".memorylist", "w"); + if (fp == NULL) + return; + } + +#ifdef MEM_LIST + fprintf(fp," Last %li MEMORY ALLOCATED : %lu, MAX was %lu\n", + nbBytes, debugMemSize, debugMaxMemSize); + fprintf(fp,"BLOCK NUMBER SIZE TYPE\n"); + idx = 0; + xmlMutexLock(xmlMemMutex); + p = memlist; + while ((p) && (nbBytes > 0)) { + fprintf(fp,"%-5u %6lu %6lu ",idx++,p->mh_number, + (unsigned long)p->mh_size); + switch (p->mh_type) { + case STRDUP_TYPE:fprintf(fp,"strdup() in ");break; + case MALLOC_TYPE:fprintf(fp,"malloc() in ");break; + case REALLOC_TYPE:fprintf(fp,"realloc() in ");break; + case MALLOC_ATOMIC_TYPE:fprintf(fp,"atomicmalloc() in ");break; + case REALLOC_ATOMIC_TYPE:fprintf(fp,"atomicrealloc() in ");break; + default: + fprintf(fp,"Unknown memory block, may be corrupted"); + xmlMutexUnlock(xmlMemMutex); + if (old_fp == NULL) + fclose(fp); + return; + } + if (p->mh_file != NULL) fprintf(fp,"%s(%u)", p->mh_file, p->mh_line); + if (p->mh_tag != MEMTAG) + fprintf(fp," INVALID"); + nb++; + if (nb < 100) + xmlMemContentShow(fp, p); + else + fprintf(fp," skip"); + + fprintf(fp,"\n"); + nbBytes -= (unsigned long)p->mh_size; + p = p->mh_next; + } + xmlMutexUnlock(xmlMemMutex); +#else + fprintf(fp,"Memory list not compiled (MEM_LIST not defined !)\n"); +#endif + if (old_fp == NULL) + fclose(fp); +} + /** * xmlMemDisplay: * @fp: a FILE descriptor used as the output file, if NULL, the result is @@ -665,7 +738,7 @@ xmlMemDisplay(FILE *fp) fprintf(fp," %s\n\n", buf); #endif - + fprintf(fp," MEMORY ALLOCATED : %lu, MAX was %lu\n", debugMemSize, debugMaxMemSize); fprintf(fp,"BLOCK NUMBER SIZE TYPE\n"); @@ -742,7 +815,7 @@ static void debugmem_list_delete(MEMHDR *p) * * internal error function. */ - + static void debugmem_tag_error(void *p) { xmlGenericError(xmlGenericErrorContext, @@ -802,7 +875,7 @@ xmlMemShow(FILE *fp, int nr ATTRIBUTE_UNUSED) } } xmlMutexUnlock(xmlMemMutex); -#endif /* MEM_LIST */ +#endif /* MEM_LIST */ } /** @@ -849,11 +922,11 @@ xmlInitMemory(void) { #ifdef HAVE_STDLIB_H char *breakpoint; -#endif +#endif #ifdef DEBUG_MEMORY xmlGenericError(xmlGenericErrorContext, "xmlInitMemory()\n"); -#endif +#endif /* This is really not good code (see Bug 130419). Suggestions for improvement will be welcome! @@ -867,18 +940,18 @@ xmlInitMemory(void) if (breakpoint != NULL) { sscanf(breakpoint, "%ud", &xmlMemStopAtBlock); } -#endif +#endif #ifdef HAVE_STDLIB_H breakpoint = getenv("XML_MEM_TRACE"); if (breakpoint != NULL) { sscanf(breakpoint, "%p", &xmlMemTraceBlockAt); } -#endif - +#endif + #ifdef DEBUG_MEMORY xmlGenericError(xmlGenericErrorContext, "xmlInitMemory() Ok\n"); -#endif +#endif return(0); } @@ -893,7 +966,7 @@ xmlCleanupMemory(void) { #ifdef DEBUG_MEMORY xmlGenericError(xmlGenericErrorContext, "xmlCleanupMemory()\n"); -#endif +#endif if (xmlMemInitialized == 0) return; @@ -903,7 +976,7 @@ xmlCleanupMemory(void) { #ifdef DEBUG_MEMORY xmlGenericError(xmlGenericErrorContext, "xmlCleanupMemory() Ok\n"); -#endif +#endif } /** @@ -927,7 +1000,7 @@ xmlMemSetup(xmlFreeFunc freeFunc, xmlMallocFunc mallocFunc, #ifdef DEBUG_MEMORY xmlGenericError(xmlGenericErrorContext, "xmlMemSetup()\n"); -#endif +#endif if (freeFunc == NULL) return(-1); if (mallocFunc == NULL) @@ -944,7 +1017,7 @@ xmlMemSetup(xmlFreeFunc freeFunc, xmlMallocFunc mallocFunc, #ifdef DEBUG_MEMORY xmlGenericError(xmlGenericErrorContext, "xmlMemSetup() Ok\n"); -#endif +#endif return(0); } @@ -994,7 +1067,7 @@ xmlGcMemSetup(xmlFreeFunc freeFunc, xmlMallocFunc mallocFunc, #ifdef DEBUG_MEMORY xmlGenericError(xmlGenericErrorContext, "xmlGcMemSetup()\n"); -#endif +#endif if (freeFunc == NULL) return(-1); if (mallocFunc == NULL) @@ -1013,7 +1086,7 @@ xmlGcMemSetup(xmlFreeFunc freeFunc, xmlMallocFunc mallocFunc, #ifdef DEBUG_MEMORY xmlGenericError(xmlGenericErrorContext, "xmlGcMemSetup() Ok\n"); -#endif +#endif return(0); }