ICU-21410 fix int32_t overflow in listFormat
See #1479
diff --git a/icu4c/source/i18n/formatted_string_builder.cpp b/icu4c/source/i18n/formatted_string_builder.cpp
index 5aabc31..b370f14 100644
--- a/icu4c/source/i18n/formatted_string_builder.cpp
+++ b/icu4c/source/i18n/formatted_string_builder.cpp
@@ -276,6 +276,11 @@
char16_t *oldChars = getCharPtr();
Field *oldFields = getFieldPtr();
if (fLength + count > oldCapacity) {
+ if ((fLength + count) > INT32_MAX / 2) {
+ // If we continue, then newCapacity will overlow int32_t in the next line.
+ status = U_INPUT_TOO_LONG_ERROR;
+ return -1;
+ }
int32_t newCapacity = (fLength + count) * 2;
int32_t newZero = newCapacity / 2 - (fLength + count) / 2;
@@ -330,12 +335,14 @@
fZero = newZero;
fLength += count;
}
+ U_ASSERT((fZero + index) >= 0);
return fZero + index;
}
int32_t FormattedStringBuilder::remove(int32_t index, int32_t count) {
// TODO: Reset the heap here? (If the string after removal can fit on stack?)
int32_t position = index + fZero;
+ U_ASSERT(position >= 0);
uprv_memmove2(getCharPtr() + position,
getCharPtr() + position + count,
sizeof(char16_t) * (fLength - index - count));
diff --git a/icu4c/source/test/intltest/listformattertest.cpp b/icu4c/source/test/intltest/listformattertest.cpp
index 513d63e..34536e6 100644
--- a/icu4c/source/test/intltest/listformattertest.cpp
+++ b/icu4c/source/test/intltest/listformattertest.cpp
@@ -49,6 +49,7 @@
TESTCASE_AUTO(TestCreateStyled);
TESTCASE_AUTO(TestContextual);
TESTCASE_AUTO(TestNextPosition);
+ TESTCASE_AUTO(TestInt32Overflow);
TESTCASE_AUTO_END;
}
@@ -828,4 +829,20 @@
}
}
+void ListFormatterTest::TestInt32Overflow() {
+ if (quick) {
+ return;
+ }
+ IcuTestErrorCode status(*this, "TestInt32Overflow");
+ LocalPointer<ListFormatter> fmt(ListFormatter::createInstance("en", status), status);
+ std::vector<UnicodeString> inputs;
+ UnicodeString input(0xAAAFF00, 0x00000042, 0xAAAFF00);
+ for (int32_t i = 0; i < 16; i++) {
+ inputs.push_back(input);
+ }
+ FormattedList result = fmt->formatStringsToValue(
+ inputs.data(), static_cast<int32_t>(inputs.size()), status);
+ status.expectErrorAndReset(U_INPUT_TOO_LONG_ERROR);
+}
+
#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/icu4c/source/test/intltest/listformattertest.h b/icu4c/source/test/intltest/listformattertest.h
index b3d4005..aeba483 100644
--- a/icu4c/source/test/intltest/listformattertest.h
+++ b/icu4c/source/test/intltest/listformattertest.h
@@ -56,6 +56,7 @@
void TestCreateStyled();
void TestContextual();
void TestNextPosition();
+ void TestInt32Overflow();
private:
void CheckFormatting(