From 4a3ba8eee90ea1414d4f7ee36563e6c9b28fda96 Mon Sep 17 00:00:00 2001 From: Yoshito Umaoka Date: Wed, 20 Jun 2018 05:34:56 +0000 Subject: [PATCH] ICU-13823 Merged #13840 number parser memory overflow fix (r41541) to maint-62 for 62.1 GA. X-SVN-Rev: 41542 --- icu4c/source/i18n/number_decimalquantity.cpp | 2 +- icu4c/source/test/intltest/numfmtst.cpp | 31 +++++++++++++++++++ icu4c/source/test/intltest/numfmtst.h | 1 + .../icu/dev/test/format/NumberFormatTest.java | 23 ++++++++++++++ 4 files changed, 56 insertions(+), 1 deletion(-) diff --git a/icu4c/source/i18n/number_decimalquantity.cpp b/icu4c/source/i18n/number_decimalquantity.cpp index 88304190dbb..9d80e3349cb 100644 --- a/icu4c/source/i18n/number_decimalquantity.cpp +++ b/icu4c/source/i18n/number_decimalquantity.cpp @@ -1058,7 +1058,7 @@ void DecimalQuantity::ensureCapacity(int32_t capacity) { auto bcd1 = static_cast(uprv_malloc(capacity * 2 * sizeof(int8_t))); uprv_memcpy(bcd1, fBCD.bcdBytes.ptr, oldCapacity * sizeof(int8_t)); // Initialize the rest of the byte array to zeros (this is done automatically in Java) - uprv_memset(fBCD.bcdBytes.ptr + oldCapacity, 0, (capacity - oldCapacity) * sizeof(int8_t)); + uprv_memset(bcd1 + oldCapacity, 0, (capacity - oldCapacity) * sizeof(int8_t)); uprv_free(fBCD.bcdBytes.ptr); fBCD.bcdBytes.ptr = bcd1; fBCD.bcdBytes.len = capacity * 2; diff --git a/icu4c/source/test/intltest/numfmtst.cpp b/icu4c/source/test/intltest/numfmtst.cpp index f5fb64e1eb9..b7184296e4a 100644 --- a/icu4c/source/test/intltest/numfmtst.cpp +++ b/icu4c/source/test/intltest/numfmtst.cpp @@ -215,6 +215,7 @@ void NumberFormatTest::runIndexedTest( int32_t index, UBool exec, const char* &n TESTCASE_AUTO(Test13763_FieldPositionIteratorOffset); TESTCASE_AUTO(Test13777_ParseLongNameNonCurrencyMode); TESTCASE_AUTO(Test13804_EmptyStringsWhenParsing); + TESTCASE_AUTO(Test13840_ParseLongStringCrash); TESTCASE_AUTO_END; } @@ -9154,4 +9155,34 @@ void NumberFormatTest::Test13804_EmptyStringsWhenParsing() { } } +void NumberFormatTest::Test13840_ParseLongStringCrash() { + IcuTestErrorCode status(*this, "Test13840_ParseLongStringCrash"); + + LocalPointer nf(NumberFormat::createInstance("en", status), status); + if (status.errIfFailureAndReset()) { return; } + + Formattable result; + static const char16_t* bigString = + u"111111111111111111111111111111111111111111111111111111111111111111111" + u"111111111111111111111111111111111111111111111111111111111111111111111" + u"111111111111111111111111111111111111111111111111111111111111111111111" + u"111111111111111111111111111111111111111111111111111111111111111111111" + u"111111111111111111111111111111111111111111111111111111111111111111111" + u"111111111111111111111111111111111111111111111111111111111111111111111"; + nf->parse(bigString, result, status); + + // Normalize the input string: + CharString expectedChars; + expectedChars.appendInvariantChars(bigString, status); + DecimalQuantity expectedDQ; + expectedDQ.setToDecNumber(expectedChars.toStringPiece(), status); + UnicodeString expectedUString = expectedDQ.toScientificString(); + + // Get the output string: + StringPiece actualChars = result.getDecimalNumber(status); + UnicodeString actualUString = UnicodeString(actualChars.data(), actualChars.length(), US_INV); + + assertEquals("Should round-trip without crashing", expectedUString, actualUString); +} + #endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/icu4c/source/test/intltest/numfmtst.h b/icu4c/source/test/intltest/numfmtst.h index 1c7c8622964..b51e752517e 100644 --- a/icu4c/source/test/intltest/numfmtst.h +++ b/icu4c/source/test/intltest/numfmtst.h @@ -279,6 +279,7 @@ class NumberFormatTest: public CalendarTimeZoneTest { void Test13763_FieldPositionIteratorOffset(); void Test13777_ParseLongNameNonCurrencyMode(); void Test13804_EmptyStringsWhenParsing(); + void Test13840_ParseLongStringCrash(); private: UBool testFormattableAsUFormattable(const char *file, int line, Formattable &f); diff --git a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/NumberFormatTest.java b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/NumberFormatTest.java index 78bf6b56eba..effd33f3d0d 100644 --- a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/NumberFormatTest.java +++ b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/NumberFormatTest.java @@ -6223,4 +6223,27 @@ public class NumberFormatTest extends TestFmwk { df.parse("1E+2.3", ppos); } } + + @Test + public void test13840_ParseLongStringCrash() throws ParseException { + NumberFormat nf = NumberFormat.getInstance(ULocale.ENGLISH); + String bigString = + "111111111111111111111111111111111111111111111111111111111111111111111" + + "111111111111111111111111111111111111111111111111111111111111111111111" + + "111111111111111111111111111111111111111111111111111111111111111111111" + + "111111111111111111111111111111111111111111111111111111111111111111111" + + "111111111111111111111111111111111111111111111111111111111111111111111" + + "111111111111111111111111111111111111111111111111111111111111111111111"; + Number result = nf.parse(bigString); + + // Normalize the input string: + BigDecimal expectedBigDecimal = new BigDecimal(bigString); + String expectedUString = expectedBigDecimal.toString(); + + // Get the output string: + BigDecimal actualBigDecimal = (BigDecimal) result; + String actualUString = actualBigDecimal.toString(); + + assertEquals("Should round-trip without crashing", expectedUString, actualUString); + } }