From: Amos Jeffries Date: Fri, 19 Dec 2014 16:26:44 +0000 (-0800) Subject: MemPool the debug output stream buffers X-Git-Tag: merge-candidate-3-v1~427 X-Git-Url: http://git.ipfire.org/gitweb/gitweb.cgi?a=commitdiff_plain;h=bfa0977917b3f2239615878e6e07e6e8eb0f9020;p=thirdparty%2Fsquid.git MemPool the debug output stream buffers The CurrentDebug output stream controller for cache.log was defined as a std::ostringstream object and allocated with new/delete on each call to debugs(). The std::ostringstream is defined as a templates output stream which uses the std::allocator built into libc when its new()'d. Since this is all internal to the STL library definitions it links against the libc global-scope allocator. However, there is no matching deallocator definition and when the object is delete()'d the standard C++ operator overloading rules make the global-scope SquidNew.h definition of ::operator delete() be the method of deallocation. That uses free() internally. To resolve the mismatch of new()/free() we must define a wrapper class with explicit class-scope new/delete operators instead of relying on weak linkages to overloaded global scope operators. As a result the memory is new()'d and free()'d. As detected by Valgrind --- diff --git a/src/Debug.h b/src/Debug.h index 7d0509a42a..41ea2fe610 100644 --- a/src/Debug.h +++ b/src/Debug.h @@ -67,7 +67,19 @@ private: // Hack: replaces global ::xassert() to debug debugging assertions static void xassert(const char *msg, const char *file, int line); - static std::ostringstream *CurrentDebug; + /// Wrapper class to prevent SquidNew.h overrides getting confused + /// with the libc++6 std::ostringstream definitions + class OutStream : public std::ostringstream + { + // XXX: use MEMPROXY_CLASS() once that no longer pulls in typedefs.h and enums.h and globals.h + public: + void *operator new(size_t size) throw(std::bad_alloc) {return xmalloc(size);} + void operator delete(void *address) throw() {xfree(address);} + void *operator new[] (size_t size) throw(std::bad_alloc) ; //{return xmalloc(size);} + void operator delete[] (void *address) throw() ; // {xfree(address);} + }; + + static OutStream *CurrentDebug; static int TheDepth; // level of nested debugging calls }; diff --git a/src/debug.cc b/src/debug.cc index 869dd37657..1d6335196f 100644 --- a/src/debug.cc +++ b/src/debug.cc @@ -709,6 +709,8 @@ ctx_get_descr(Ctx ctx) int Debug::TheDepth = 0; +Debug::OutStream *Debug::CurrentDebug(NULL); + std::ostream & Debug::getDebugOut() { @@ -719,7 +721,7 @@ Debug::getDebugOut() *CurrentDebug << std::endl << "reentrant debuging " << TheDepth << "-{"; } else { assert(!CurrentDebug); - CurrentDebug = new std::ostringstream(); + CurrentDebug = new Debug::OutStream; // set default formatting flags CurrentDebug->setf(std::ios::fixed); CurrentDebug->precision(2); @@ -756,8 +758,6 @@ Debug::xassert(const char *msg, const char *file, int line) abort(); } -std::ostringstream (*Debug::CurrentDebug)(NULL); - size_t BuildPrefixInit() { diff --git a/src/tests/stub_debug.cc b/src/tests/stub_debug.cc index 7412640120..dea7c3c76e 100644 --- a/src/tests/stub_debug.cc +++ b/src/tests/stub_debug.cc @@ -87,6 +87,8 @@ _db_print_stderr(const char *format, va_list args) vfprintf(stderr, format, args); } +Debug::OutStream *Debug::CurrentDebug(NULL); + std::ostream & Debug::getDebugOut() { @@ -97,7 +99,7 @@ Debug::getDebugOut() *CurrentDebug << std::endl << "reentrant debuging " << TheDepth << "-{"; } else { assert(!CurrentDebug); - CurrentDebug = new std::ostringstream(); + CurrentDebug = new Debug::OutStream; // set default formatting flags CurrentDebug->setf(std::ios::fixed); CurrentDebug->precision(2); @@ -138,8 +140,6 @@ Debug::xassert(const char *msg, const char *file, int line) abort(); } -std::ostringstream *Debug::CurrentDebug (NULL); - const char* SkipBuildPrefix(const char* path) {