From 0d5b662f8bd3ce7ca82372ec42427d3d3d1ae040 Mon Sep 17 00:00:00 2001 From: Frank Tang Date: Sat, 1 Feb 2020 02:39:04 +0000 Subject: [PATCH] ICU-20958 Prevent SEGV_MAPERR in append See #971 (cherry picked from commit b7d08bc04a4296982fcef8b6b8a354a9e4e7afca) --- icu4c/source/common/unistr.cpp | 21 ++++++++++++++++++++- icu4c/source/test/intltest/ustrtest.cpp | 3 ++- icu4c/source/test/intltest/ustrtest.h | 2 ++ 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/icu4c/source/common/unistr.cpp b/icu4c/source/common/unistr.cpp index d5b8ffa295d9..43b755d28561 100644 --- a/icu4c/source/common/unistr.cpp +++ b/icu4c/source/common/unistr.cpp @@ -1564,7 +1564,26 @@ UnicodeString::doAppend(const UChar *srcChars, int32_t srcStart, int32_t srcLeng } int32_t oldLength = length(); - int32_t newLength = oldLength + srcLength; + int32_t newLength; + if (uprv_add32_overflow(oldLength, srcLength, &newLength)) { + setToBogus(); + return *this; + } + + // Check for append onto ourself + const UChar* oldArray = getArrayStart(); + if (isBufferWritable() && + oldArray < srcChars + srcLength && + srcChars < oldArray + oldLength) { + // Copy into a new UnicodeString and start over + UnicodeString copy(srcChars, srcLength); + if (copy.isBogus()) { + setToBogus(); + return *this; + } + return doAppend(copy.getArrayStart(), 0, srcLength); + } + // optimize append() onto a large-enough, owned string if((newLength <= getCapacity() && isBufferWritable()) || cloneArrayIfNeeded(newLength, getGrowCapacity(newLength))) { diff --git a/icu4c/source/test/intltest/ustrtest.cpp b/icu4c/source/test/intltest/ustrtest.cpp index ff435cc48d71..9c7d607136f2 100644 --- a/icu4c/source/test/intltest/ustrtest.cpp +++ b/icu4c/source/test/intltest/ustrtest.cpp @@ -64,6 +64,8 @@ void UnicodeStringTest::runIndexedTest( int32_t index, UBool exec, const char* & TESTCASE_AUTO(TestUInt16Pointers); TESTCASE_AUTO(TestWCharPointers); TESTCASE_AUTO(TestNullPointers); + TESTCASE_AUTO(TestUnicodeStringInsertAppendToSelf); + TESTCASE_AUTO(TestLargeAppend); TESTCASE_AUTO_END; } @@ -2246,7 +2248,6 @@ UnicodeStringTest::TestNullPointers() { UnicodeString(u"def").extract(nullptr, 0, errorCode); assertEquals("buffer overflow extracting to nullptr", U_BUFFER_OVERFLOW_ERROR, errorCode); } - void UnicodeStringTest::TestUnicodeStringInsertAppendToSelf() { IcuTestErrorCode status(*this, "TestUnicodeStringAppendToSelf"); diff --git a/icu4c/source/test/intltest/ustrtest.h b/icu4c/source/test/intltest/ustrtest.h index 4ba348c431fd..4a356a92c7a5 100644 --- a/icu4c/source/test/intltest/ustrtest.h +++ b/icu4c/source/test/intltest/ustrtest.h @@ -96,6 +96,8 @@ class UnicodeStringTest: public IntlTest { void TestUInt16Pointers(); void TestWCharPointers(); void TestNullPointers(); + void TestUnicodeStringInsertAppendToSelf(); + void TestLargeAppend(); }; #endif