From 962b1cf441ceb1de7791d89951a79a54a2fefcd4 Mon Sep 17 00:00:00 2001 From: Gavin Andresen Date: Tue, 10 Dec 2013 11:34:28 +1000 Subject: [PATCH 1/2] Fix infinite loop with LogPrint on Windows Running -printtodebugger -debug (or -debug=lock), compiled with -DDEBUG_LOCKORDER would infinite loop on Windows because every critical section lock/unlock triggers a LogPrint. Solution is to use the raw boost mutex instead of a CCriticalSection. --- src/util.cpp | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/src/util.cpp b/src/util.cpp index a8c591cc7..d975cc9bf 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -299,27 +299,24 @@ int LogPrint(const char* category, const char* pszFormat, ...) #ifdef WIN32 if (fPrintToDebugger) { - static CCriticalSection cs_OutputDebugStringF; - // accumulate and output a line at a time + static std::string buffer; + + boost::mutex::scoped_lock scoped_lock(*mutexDebugLog); + + va_list arg_ptr; + va_start(arg_ptr, pszFormat); + buffer += vstrprintf(pszFormat, arg_ptr); + va_end(arg_ptr); + + int line_start = 0, line_end; + while((line_end = buffer.find('\n', line_start)) != -1) { - LOCK(cs_OutputDebugStringF); - static std::string buffer; - - va_list arg_ptr; - va_start(arg_ptr, pszFormat); - buffer += vstrprintf(pszFormat, arg_ptr); - va_end(arg_ptr); - - int line_start = 0, line_end; - while((line_end = buffer.find('\n', line_start)) != -1) - { - OutputDebugStringA(buffer.substr(line_start, line_end - line_start).c_str()); - line_start = line_end + 1; - ret += line_end-line_start; - } - buffer.erase(0, line_start); + OutputDebugStringA(buffer.substr(line_start, line_end - line_start).c_str()); + line_start = line_end + 1; + ret += line_end-line_start; } + buffer.erase(0, line_start); } #endif return ret; From 0b238b278686f8e0c6609b7c9360d36c3198105c Mon Sep 17 00:00:00 2001 From: Gavin Andresen Date: Tue, 10 Dec 2013 13:19:18 +1000 Subject: [PATCH 2/2] Use thread-local storage for LogPrint(category...) This prevents crashes at shutdown where a global destructor calls LogPrint(category...) after mapMultiArgs has been deleted. --- src/util.cpp | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/util.cpp b/src/util.cpp index d975cc9bf..bedf59767 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -242,17 +242,23 @@ int LogPrint(const char* category, const char* pszFormat, ...) if (!fDebug) return 0; - const vector& categories = mapMultiArgs["-debug"]; - bool allCategories = count(categories.begin(), categories.end(), string("")); - - // Only look for categories, if not -debug/-debug=1 was passed, - // as that implies every category should be logged. - if (!allCategories) + // Give each thread quick access to -debug settings. + // This helps prevent issues debugging global destructors, + // where mapMultiArgs might be deleted before another + // global destructor calls LogPrint() + static boost::thread_specific_ptr > ptrCategory; + if (ptrCategory.get() == NULL) { - // Category was not found (not supplied via -debug=) - if (find(categories.begin(), categories.end(), string(category)) == categories.end()) - return 0; + const vector& categories = mapMultiArgs["-debug"]; + ptrCategory.reset(new set(categories.begin(), categories.end())); + // thread_specific_ptr automatically deletes the set when the thread ends. } + const set& setCategories = *ptrCategory.get(); + + // if not debugging everything and not debugging specific category, LogPrint does nothing. + if (setCategories.count(string("")) == 0 && + setCategories.count(string(category)) == 0) + return 0; } int ret = 0; // Returns total number of characters written