diff --git a/CMakeLists.txt b/CMakeLists.txt index d3a7f0f..8f0b99b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -72,6 +72,27 @@ else () add_definitions ( -DSUPPORT_CONSOLE_APP=0 ) endif () +# Enable building with some memory diagnostics +# NOTE: Only available in the Debug configuration build in Windows +# but could be maybe extended to unix, mac... +if (WIN32) + option( ENABLE_MEMORY_DEBUG "Set ON to output some memory diagnostics." OFF ) + option( ENABLE_ALLOC_DEBUG "Set ON to output node allocation diagnostics." OFF ) + option( ENABLE_CRTDBG_MEMORY "Set ON to enable the Windows CRT debug library." OFF ) + if (ENABLE_MEMORY_DEBUG) + add_definitions ( -DDEBUG_MEMORY ) # see alloc.c for details + message(STATUS "*** Note, alloc.c memory diagnostics are ON") + endif () + if (ENABLE_ALLOC_DEBUG) + add_definitions ( -DDEBUG_ALLOCATION ) # see lexer.c for details + message(STATUS "*** Note, lexer.c node allocation diagnostics are ON") + endif () + if (ENABLE_CRTDBG_MEMORY) + add_definitions ( -D_CRTDBG_MAP_ALLOC ) # see tidy.c for details + message(STATUS "*** Note, tidy.c Windows CRT memory debug is ON") + endif () +endif () + if(CMAKE_COMPILER_IS_GNUCXX) set( WARNING_FLAGS -Wall ) endif(CMAKE_COMPILER_IS_GNUCXX) diff --git a/console/tidy.c b/console/tidy.c index bc5b4e8..281ca3c 100644 --- a/console/tidy.c +++ b/console/tidy.c @@ -27,6 +27,10 @@ #endif #if !defined(NDEBUG) && defined(_MSC_VER) #include "sprtf.h" +#ifdef _CRTDBG_MAP_ALLOC +#include +#include +#endif #endif #ifndef SPRTF @@ -1882,7 +1886,7 @@ int main( int argc, char** argv ) { ctmbstr prog = argv[0]; ctmbstr cfgfil = NULL, errfil = NULL, htmlfil = NULL; - TidyDoc tdoc = tidyCreate(); + TidyDoc tdoc = NULL; int status = 0; tmbstr locale = NULL; @@ -1890,6 +1894,16 @@ int main( int argc, char** argv ) uint contentWarnings = 0; uint accessWarnings = 0; +#if !defined(NDEBUG) && defined(_MSC_VER) +#if defined(_CRTDBG_MAP_ALLOC) + _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); +#endif + set_log_file((char *)"temptidy.txt", 0); + /* add_append_log(1); */ +#endif + + tdoc = tidyCreate(); + tidySetMessageCallback( tdoc, reportCallback); /* experimental group */ errout = stderr; /* initialize to stderr */ @@ -1914,12 +1928,6 @@ int main( int argc, char** argv ) SetConsoleOutputCP(CP_UTF8); #endif - -#if !defined(NDEBUG) && defined(_MSC_VER) - set_log_file((char *)"temptidy.txt", 0); - /* add_append_log(1); */ -#endif - /* * Look for default configuration files using any of * the following possibilities: diff --git a/src/alloc.c b/src/alloc.c index 8cf0856..326be35 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -18,6 +18,13 @@ static TidyRealloc g_realloc = NULL; static TidyFree g_free = NULL; static TidyPanic g_panic = NULL; +#if !defined(NDEBUG) && defined(_MSC_VER) && defined(DEBUG_MEMORY) +static int alloccnt = 0; +static int realloccnt = 0; +static int freecnt = 0; +#endif + + Bool TIDY_CALL tidySetMallocCall( TidyMalloc fmalloc ) { g_malloc = fmalloc; @@ -60,7 +67,8 @@ static void* TIDY_CALL defaultAlloc( TidyAllocator* allocator, size_t size ) if ( !p ) defaultPanic( allocator,"Out of memory!"); #if !defined(NDEBUG) && defined(_MSC_VER) && defined(DEBUG_MEMORY) - SPRTF("alloc MEM %p, size %d\n", p, (int)size ); + alloccnt++; + SPRTF("%d: alloc MEM %p, size %d\n", alloccnt, p, (int)size ); if (size == 0) { SPRTF("NOTE: An allocation of ZERO bytes!!!!!!\n"); } @@ -78,7 +86,8 @@ static void* TIDY_CALL defaultRealloc( TidyAllocator* allocator, void* mem, size if (!p) defaultPanic( allocator, "Out of memory!"); #if !defined(NDEBUG) && defined(_MSC_VER) && defined(DEBUG_MEMORY) - SPRTF("realloc MEM %p, size %d\n", p, (int)newsize ); + realloccnt++; + SPRTF("%d: realloc MEM %p, size %d\n", realloccnt, p, (int)newsize ); #endif return p; } @@ -88,7 +97,8 @@ static void TIDY_CALL defaultFree( TidyAllocator* ARG_UNUSED(allocator), void* m if ( mem ) { #if !defined(NDEBUG) && defined(_MSC_VER) && defined(DEBUG_MEMORY) - SPRTF("free MEM %p\n", mem ); + freecnt++; + SPRTF("%d: free MEM %p\n", freecnt, mem ); #endif if ( g_free ) g_free( mem ); diff --git a/src/lexer.c b/src/lexer.c index 970f044..a23ed8e 100644 --- a/src/lexer.c +++ b/src/lexer.c @@ -1551,7 +1551,15 @@ void TY_(RemoveAttribute)( TidyDocImpl* doc, Node *node, AttVal *attr ) void TY_(FreeNode)( TidyDocImpl* doc, Node *node ) { #if !defined(NDEBUG) && defined(_MSC_VER) && defined(DEBUG_ALLOCATION) - if (node) SPRTF("Free node %p\n", node ); + /* avoid showing free of root node! */ + if (node) { + if (RootNode != node->type) { + SPRTF("Free node %p\n", node); + } + else { + SPRTF("Root node %p\n", node); + } + } #endif /* this is no good ;=(( if (node && doc && doc->lexer) { diff --git a/src/messageobj.c b/src/messageobj.c index 3156356..8be94b1 100644 --- a/src/messageobj.c +++ b/src/messageobj.c @@ -256,6 +256,7 @@ void TY_(tidyMessageRelease)( TidyMessageImpl *message ) TidyDocFree( tidyDocToImpl(message->tidyDoc), message->messagePos ); TidyDocFree( tidyDocToImpl(message->tidyDoc), message->messageOutputDefault ); TidyDocFree( tidyDocToImpl(message->tidyDoc), message->messageOutput ); + TidyDocFree(tidyDocToImpl(message->tidyDoc), message); /* Issue #597 - and discard the message structure */ } diff --git a/src/parser.c b/src/parser.c index 56660aa..168823c 100644 --- a/src/parser.c +++ b/src/parser.c @@ -1361,9 +1361,16 @@ void TY_(ParseBlock)( TidyDocImpl* doc, Node *element, GetTokenMode mode) if (nodeIsA(element)) { + TY_(Report)(doc, element, node, MISSING_ENDTAG_BEFORE); TY_(UngetToken)( doc ); } - TY_(Report)(doc, element, node, MISSING_ENDTAG_BEFORE); + else + { + /* Issue #597 - if we not 'UngetToken' then it is being discarded. + Add message, and 'FreeNode' - thanks @ralfjunker */ + TY_(Report)(doc, element, node, DISCARDING_UNEXPECTED); + TY_(FreeNode)(doc, node); + } if (!(mode & Preformatted)) TrimSpaces(doc, element); diff --git a/src/sprtf.c b/src/sprtf.c index 7e18868..3c5cff9 100644 --- a/src/sprtf.c +++ b/src/sprtf.c @@ -294,7 +294,7 @@ static void oi( char * psin ) } if( addstdout ) { - fwrite( ps, 1, len, stdout ); + fwrite( ps, 1, len, stderr ); /* 20170917 - Switch to using 'stderr' in place of 'stdout' */ } #ifdef ADD_LISTVIEW if (add2listview) {