From 94aeaa02bf4809ddd5f59627093a64fe4aeb875b Mon Sep 17 00:00:00 2001 From: jabberwock <88205+jabberwock@users.noreply.github.com> Date: Tue, 17 Mar 2026 08:52:33 -0700 Subject: [PATCH 1/2] Message: add bounds check in GetParamsColon when uIdx >= params.size() Without this check, when uIdx >= m_vsParams.size() and the vector is non-empty, the subtraction in the clamp condition underflows to SIZE_MAX. GetParamsSplit() already has the equivalent check at the top of the function; this brings GetParamsColon() in line with it. Fixes #1994 --- src/Message.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Message.cpp b/src/Message.cpp index 64fa7950..71369a7f 100644 --- a/src/Message.cpp +++ b/src/Message.cpp @@ -51,7 +51,7 @@ void CMessage::SetCommand(const CString& sCommand) { } CString CMessage::GetParamsColon(unsigned int uIdx, unsigned int uLen) const { - if (m_vsParams.empty() || uLen == 0) { + if (m_vsParams.empty() || uLen == 0 || uIdx >= m_vsParams.size()) { return ""; } if (uLen > m_vsParams.size() - uIdx - 1) { From 20908fc2d1c0b5e7cdab434eeb2c28b909e2e702 Mon Sep 17 00:00:00 2001 From: jabberwock <88205+jabberwock@users.noreply.github.com> Date: Tue, 17 Mar 2026 09:37:02 -0700 Subject: [PATCH 2/2] test: add GetParamsColon unit tests including out-of-bounds uIdx cases --- test/MessageTest.cpp | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/test/MessageTest.cpp b/test/MessageTest.cpp index f54c4a89..38fb847f 100644 --- a/test/MessageTest.cpp +++ b/test/MessageTest.cpp @@ -72,6 +72,40 @@ TEST(MessageTest, GetParams) { EXPECT_EQ(CMessage("CMD p1 :p2 p3").GetParams(-1, 10), ""); } +TEST(MessageTest, GetParamsColon) { + EXPECT_EQ(CMessage("CMD").GetParamsColon(0), ""); + EXPECT_EQ(CMessage("CMD").GetParamsColon(1), ""); + EXPECT_EQ(CMessage("CMD").GetParamsColon(-1), ""); + + EXPECT_EQ(CMessage("CMD").GetParamsColon(0, 0), ""); + EXPECT_EQ(CMessage("CMD").GetParamsColon(1, 0), ""); + EXPECT_EQ(CMessage("CMD").GetParamsColon(-1, 0), ""); + + EXPECT_EQ(CMessage("CMD").GetParamsColon(0, 1), ""); + EXPECT_EQ(CMessage("CMD").GetParamsColon(1, 1), ""); + EXPECT_EQ(CMessage("CMD").GetParamsColon(-1, 1), ""); + + EXPECT_EQ(CMessage("CMD p1 :p2 p3").GetParamsColon(0), "p1 :p2 p3"); + EXPECT_EQ(CMessage("CMD p1 :p2 p3").GetParamsColon(1), ":p2 p3"); + EXPECT_EQ(CMessage("CMD p1 :p2 p3").GetParamsColon(-1), ""); + + EXPECT_EQ(CMessage("CMD p1 :p2 p3").GetParamsColon(0, 0), ""); + EXPECT_EQ(CMessage("CMD p1 :p2 p3").GetParamsColon(1, 0), ""); + EXPECT_EQ(CMessage("CMD p1 :p2 p3").GetParamsColon(-1, 0), ""); + + EXPECT_EQ(CMessage("CMD p1 :p2 p3").GetParamsColon(0, 1), "p1"); + EXPECT_EQ(CMessage("CMD p1 :p2 p3").GetParamsColon(1, 1), ":p2 p3"); + EXPECT_EQ(CMessage("CMD p1 :p2 p3").GetParamsColon(-1, 1), ""); + + EXPECT_EQ(CMessage("CMD p1 :p2 p3").GetParamsColon(0, 10), "p1 :p2 p3"); + EXPECT_EQ(CMessage("CMD p1 :p2 p3").GetParamsColon(1, 10), ":p2 p3"); + EXPECT_EQ(CMessage("CMD p1 :p2 p3").GetParamsColon(-1, 10), ""); + + // uIdx past the end must return "" without undefined behaviour (#1994) + EXPECT_EQ(CMessage("MODE #chan +b").GetParamsColon(2, 1), ""); + EXPECT_EQ(CMessage("MODE #chan +b").GetParamsColon(3, 1), ""); +} + TEST(MessageTest, GetParamsSplit) { EXPECT_THAT(CMessage("CMD").GetParamsSplit(0), IsEmpty()); EXPECT_THAT(CMessage("CMD").GetParamsSplit(1), IsEmpty());