Skip to content

Commit

Permalink
ICU-21410 fix int32_t overflow in listFormat
Browse files Browse the repository at this point in the history
See #1479
  • Loading branch information
FrankYFTang committed Nov 24, 2020
1 parent 6ad0ece commit 275d59a
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 0 deletions.
7 changes: 7 additions & 0 deletions icu4c/source/i18n/formatted_string_builder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,11 @@ int32_t FormattedStringBuilder::prepareForInsertHelper(int32_t index, int32_t co
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;

Expand Down Expand Up @@ -330,12 +335,14 @@ int32_t FormattedStringBuilder::prepareForInsertHelper(int32_t index, int32_t co
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));
Expand Down
17 changes: 17 additions & 0 deletions icu4c/source/test/intltest/listformattertest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ void ListFormatterTest::runIndexedTest(int32_t index, UBool exec,
TESTCASE_AUTO(TestCreateStyled);
TESTCASE_AUTO(TestContextual);
TESTCASE_AUTO(TestNextPosition);
TESTCASE_AUTO(TestInt32Overflow);
TESTCASE_AUTO_END;
}

Expand Down Expand Up @@ -828,4 +829,20 @@ void ListFormatterTest::TestNextPosition() {
}
}

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 */
1 change: 1 addition & 0 deletions icu4c/source/test/intltest/listformattertest.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ class ListFormatterTest : public IntlTestWithFieldPosition {
void TestCreateStyled();
void TestContextual();
void TestNextPosition();
void TestInt32Overflow();

private:
void CheckFormatting(
Expand Down

0 comments on commit 275d59a

Please sign in to comment.