From 2fdbe51df5f99460752d6ddd1dcd584489f40c86 Mon Sep 17 00:00:00 2001 From: Alexey Sokolov Date: Fri, 4 Mar 2016 08:04:03 +0000 Subject: [PATCH] Fix #1248: segfault in shell module. It happened when client disconnects. --- modules/shell.cpp | 18 +++++++++++++++++ test/integration/main.cpp | 42 +++++++++++++++++++++++++++------------ 2 files changed, 47 insertions(+), 13 deletions(-) diff --git a/modules/shell.cpp b/modules/shell.cpp index 7156c27c..32deef48 100644 --- a/modules/shell.cpp +++ b/modules/shell.cpp @@ -49,6 +49,9 @@ class CShellSock : public CExecSock { void ReadLine(const CString& sData) override; void Disconnected() override; + bool IsOfClient(CClient* pClient) const { return pClient == m_pClient; } + bool IsOfModule(CShellMod* pParent) const { return pParent == m_pParent; } + CShellMod* m_pParent; private: @@ -117,6 +120,21 @@ class CShellMod : public CModule { "SHELL"); } + void OnClientDisconnect() override { + std::vector vDeadCommands; + for (Csock* pSock : *GetManager()) { + if (CShellSock* pSSock = dynamic_cast(pSock)) { + if (pSSock->IsOfModule(this) && + pSSock->IsOfClient(GetClient())) { + vDeadCommands.push_back(pSock); + } + } + } + for (Csock* pSock : vDeadCommands) { + GetManager()->DelSockByAddr(pSock); + } + } + private: CString m_sPath; }; diff --git a/test/integration/main.cpp b/test/integration/main.cpp index b3eb95fd..f3090d87 100644 --- a/test/integration/main.cpp +++ b/test/integration/main.cpp @@ -1664,19 +1664,6 @@ TEST_F(ZNCTest, ControlpanelModule) { Z; } -TEST_F(ZNCTest, ShellModule) { - auto znc = Run(); - Z; - auto ircd = ConnectIRCd(); - Z; - auto client = LoginClient(); - Z; - client.Write("znc loadmod shell"); - client.Write("PRIVMSG *shell :echo blahblah"); - client.ReadUntil("PRIVMSG nick :blahblah"); - client.ReadUntil("PRIVMSG nick :znc$"); -} - TEST_F(ZNCTest, NotifyConnectModule) { auto znc = Run(); Z; @@ -1714,6 +1701,35 @@ TEST_F(ZNCTest, NotifyConnectModule) { Z; } +TEST_F(ZNCTest, ShellModule) { + auto znc = Run(); + Z; + auto ircd = ConnectIRCd(); + Z; + auto client = LoginClient(); + Z; + client.Write("znc loadmod shell"); + client.Write("PRIVMSG *shell :echo blahblah"); + client.ReadUntil("PRIVMSG nick :blahblah"); + Z; + client.ReadUntil("PRIVMSG nick :znc$"); + Z; + + // https://github.com/znc/znc/issues/1248 + auto client2 = LoginClient(); + client2.Write("znc loadmod notify_connect"); + client.Write("PRIVMSG *shell :yes"); + client.ReadUntil(":y"); + Z; + client.Close(); + client2.ReadUntil("detached"); + // This can be racy, if no "y" appears between this two lines. I can take + // this risk though. To be extra safe, sleep 1 additional second. + // TODO: replace "yes" with socat (or netcat) connecting to a socket opened + // by this test. + sleep(1); +} + TEST_F(ZNCTest, WatchModule) { // TODO test other messages // TODO test options