From f1338fde5c05fc2fb9c703cd2334e7dfd6ba32b3 Mon Sep 17 00:00:00 2001 From: psychon Date: Thu, 10 Sep 2009 18:27:56 +0000 Subject: [PATCH] Fix a theoretical crash on shutdown CZNC::~CZNC() set its pointer to the CConnectUserTimer to NULL and then called the manager's Cleanup(). If some destructor that is called from here then calls EnableConnectUser(), a new CConnectUserTimer is created and its address is saved. But since the manager is destroying all timers, this pointer will soon become dangling and might crash us later on. This is solved by clearing CZNC's pointer in CConnectUserTimer's destructor. git-svn-id: https://znc.svn.sourceforge.net/svnroot/znc/trunk@1624 726aef4b-f618-498e-8847-2d620e286838 --- znc.cpp | 18 +++++++++++++++++- znc.h | 3 +++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/znc.cpp b/znc.cpp index d225dc31..2468d1e0 100644 --- a/znc.cpp +++ b/znc.cpp @@ -1794,7 +1794,18 @@ public: // Don't wait iSecs seconds for first timer run m_bRunOnNextCall = true; } - virtual ~CConnectUserTimer() {} + virtual ~CConnectUserTimer() { + // This is only needed when ZNC shuts down: + // CZNC::~CZNC() sets its CConnectUserTimer pointer to NULL and + // calls the manager's Cleanup() which destroys all sockets and + // timers. If something calls CZNC::EnableConnectUser() here + // (e.g. because a CIRCSock is destroyed), the socket manager + // deletes that timer almost immediately, but CZNC now got a + // dangling pointer to this timer which can crash later on. + // + // Unlikely but possible ;) + CZNC::Get().LeakConnectUser(this); + } protected: virtual void RunJob() { @@ -1870,3 +1881,8 @@ void CZNC::DisableConnectUser() { m_pConnectUserTimer->Stop(); m_pConnectUserTimer = NULL; } + +void CZNC::LeakConnectUser(CConnectUserTimer *pTimer) { + if (m_pConnectUserTimer == pTimer) + m_pConnectUserTimer = NULL; +} diff --git a/znc.h b/znc.h index 1be31120..5f8cc1a4 100644 --- a/znc.h +++ b/znc.h @@ -125,6 +125,9 @@ public: void EnableConnectUser(); void DisableConnectUser(); + // Never call this unless you are CConnectUserTimer::~CConnectUserTimer() + void LeakConnectUser(CConnectUserTimer *pTimer); + private: bool DoRehash(CString& sError); // Returns true if something was done