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