From 16c849daacc570abfde1cf70ba6e3b3fde3cd35d Mon Sep 17 00:00:00 2001 From: Alexey Sokolov Date: Thu, 7 Nov 2019 08:36:41 +0000 Subject: [PATCH] Fix crash when parsing incorrect channel modes sent by server. Sometimes certain servers don't send a argument for modes which it declared as ones which need an argument. No released version is affected. Close #1684 --- src/Chan.cpp | 21 ++++++++++++++------- test/IRCSockTest.cpp | 13 ++++++++++++- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/src/Chan.cpp b/src/Chan.cpp index 93d67f30..1b824ceb 100644 --- a/src/Chan.cpp +++ b/src/Chan.cpp @@ -300,7 +300,8 @@ void CChan::OnWho(const CString& sNick, const CString& sIdent, } } -void CChan::ModeChange(const CString& sModes, const VCString& vsModes, const CNick* pOpNick) { +void CChan::ModeChange(const CString& sModes, const VCString& vsModes, + const CNick* pOpNick) { bool bAdd = true; /* Try to find a CNick* from this channel so that pOpNick->HasPerm() @@ -319,6 +320,13 @@ void CChan::ModeChange(const CString& sModes, const VCString& vsModes, const CNi } VCString::const_iterator argIter = vsModes.begin(); + const CString sEmpty; + auto nextArg = [&]() -> const CString& { + if (argIter == vsModes.end()) { + return sEmpty; + } + return *argIter++; + }; for (unsigned int a = 0; a < sModes.size(); a++) { const char& cMode = sModes[a]; @@ -327,11 +335,10 @@ void CChan::ModeChange(const CString& sModes, const VCString& vsModes, const CNi } else if (cMode == '-') { bAdd = false; } else if (m_pNetwork->GetIRCSock()->IsPermMode(cMode)) { - CString sArg = *argIter++; + const CString& sArg = nextArg(); CNick* pNick = FindNick(sArg); if (pNick) { - char cPerm = - m_pNetwork->GetIRCSock()->GetPermFromMode(cMode); + char cPerm = m_pNetwork->GetIRCSock()->GetPermFromMode(cMode); if (cPerm) { bool bNoChange = (pNick->HasPerm(cPerm) == bAdd); @@ -389,16 +396,16 @@ void CChan::ModeChange(const CString& sModes, const VCString& vsModes, const CNi switch (m_pNetwork->GetIRCSock()->GetModeType(cMode)) { case CIRCSock::ListArg: bList = true; - sArg = *argIter++; + sArg = nextArg(); break; case CIRCSock::HasArg: - sArg = *argIter++; + sArg = nextArg(); break; case CIRCSock::NoArg: break; case CIRCSock::ArgWhenSet: if (bAdd) { - sArg = *argIter++; + sArg = nextArg(); } break; diff --git a/test/IRCSockTest.cpp b/test/IRCSockTest.cpp index 0c208a83..3771105f 100644 --- a/test/IRCSockTest.cpp +++ b/test/IRCSockTest.cpp @@ -331,7 +331,8 @@ TEST_F(IRCSockTest, OnPartMessage) { } TEST_F(IRCSockTest, StatusModes) { - m_pTestSock->ReadLine(":server 005 user PREFIX=(Yohv)!@%+ :are supported by this server"); + m_pTestSock->ReadLine( + ":server 005 user PREFIX=(Yohv)!@%+ :are supported by this server"); EXPECT_TRUE(m_pTestSock->IsPermMode('Y')); EXPECT_TRUE(m_pTestSock->IsPermMode('o')); @@ -547,3 +548,13 @@ TEST_F(IRCSockTest, StatusMsg) { EXPECT_EQ(m_pTestChan->GetBuffer().GetLine(0, *m_pTestClient), ":someone PRIVMSG @#chan :hello ops"); } + +TEST_F(IRCSockTest, ChanMode) { + // https://github.com/znc/znc/issues/1684 + m_pTestSock->ReadLine( + ":irc.znc.in 001 me :Welcome to the Internet Relay Network me"); + m_pTestSock->ReadLine( + ":irc.znc.in 005 me CHANMODES=be,f,lj,nti " + ":are supported by this server"); + m_pTestSock->ReadLine(":irc.znc.in 324 me #chan +ntf "); +}