From 697cb14f08df83f94e2ec9d1046035cdace56783 Mon Sep 17 00:00:00 2001 From: Frank Yung-Fong Tang Date: Thu, 13 Jun 2024 22:44:12 +0000 Subject: [PATCH] ICU-22798 Avoid stack overflow by return error. See #3035 --- icu4c/source/common/messagepattern.cpp | 2 +- icu4c/source/common/unicode/messagepattern.h | 1 + icu4c/source/test/intltest/msfmrgts.cpp | 18 ++++++++++++++++++ icu4c/source/test/intltest/msfmrgts.h | 1 + 4 files changed, 21 insertions(+), 1 deletion(-) diff --git a/icu4c/source/common/messagepattern.cpp b/icu4c/source/common/messagepattern.cpp index 9e318295f9a9..8f15c4ab467d 100644 --- a/icu4c/source/common/messagepattern.cpp +++ b/icu4c/source/common/messagepattern.cpp @@ -437,7 +437,7 @@ MessagePattern::parseMessage(int32_t index, int32_t msgStartLength, if(U_FAILURE(errorCode)) { return 0; } - if(nestingLevel>Part::MAX_VALUE) { + if(nestingLevel>Part::MAX_NESTED_LEVELS) { errorCode=U_INDEX_OUTOFBOUNDS_ERROR; return 0; } diff --git a/icu4c/source/common/unicode/messagepattern.h b/icu4c/source/common/unicode/messagepattern.h index 55b09bfbd4b5..daa7b62389a3 100644 --- a/icu4c/source/common/unicode/messagepattern.h +++ b/icu4c/source/common/unicode/messagepattern.h @@ -821,6 +821,7 @@ class U_COMMON_API MessagePattern : public UObject { static const int32_t MAX_LENGTH=0xffff; static const int32_t MAX_VALUE=0x7fff; + static const int32_t MAX_NESTED_LEVELS=0x03ff; // Some fields are not final because they are modified during pattern parsing. // After pattern parsing, the parts are effectively immutable. diff --git a/icu4c/source/test/intltest/msfmrgts.cpp b/icu4c/source/test/intltest/msfmrgts.cpp index 9ea1359efc41..ec031b1d6c1e 100644 --- a/icu4c/source/test/intltest/msfmrgts.cpp +++ b/icu4c/source/test/intltest/msfmrgts.cpp @@ -54,6 +54,7 @@ MessageFormatRegressionTest::runIndexedTest( int32_t index, UBool exec, const ch TESTCASE_AUTO(TestChoicePatternQuote); TESTCASE_AUTO(Test4112104); TESTCASE_AUTO(TestICU12584); + TESTCASE_AUTO(TestICU22798); TESTCASE_AUTO(TestAPI); TESTCASE_AUTO_END; } @@ -1013,6 +1014,23 @@ void MessageFormatRegressionTest::TestICU12584() { inner_msg.getFormats(count); assertEquals("Inner placeholder match", 3, count); } +void MessageFormatRegressionTest::TestICU22798() { + // Test deep nested choice will not cause stack overflow but return error + // instead. + UErrorCode status = U_ZERO_ERROR; + UnicodeString pattern; + constexpr static int testNestedLevel = 30000; + for (int i = 0; i < testNestedLevel; i++) { + pattern += u"A{0,choice,0#"; + } + pattern += u"text"; + for (int i = 0; i < testNestedLevel; i++) { + pattern += u"}a"; + } + MessageFormat msg(pattern, status); + assertEquals("Deep nested choice should cause error but not crash", + U_INDEX_OUTOFBOUNDS_ERROR, status); +} void MessageFormatRegressionTest::TestAPI() { UErrorCode status = U_ZERO_ERROR; diff --git a/icu4c/source/test/intltest/msfmrgts.h b/icu4c/source/test/intltest/msfmrgts.h index ec4ed7c126db..36dee9b8d918 100644 --- a/icu4c/source/test/intltest/msfmrgts.h +++ b/icu4c/source/test/intltest/msfmrgts.h @@ -46,6 +46,7 @@ class MessageFormatRegressionTest: public IntlTest { void TestChoicePatternQuote(); void Test4112104(); void TestICU12584(); + void TestICU22798(); void TestAPI(); protected: