1 From b7d08bc04a4296982fcef8b6b8a354a9e4e7afca Mon Sep 17 00:00:00 2001
2 From: Frank Tang <ftang@chromium.org>
3 Date: Sat, 1 Feb 2020 02:39:04 +0000
4 Subject: [PATCH] ICU-20958 Prevent SEGV_MAPERR in append
8 common/unistr.cpp | 6 ++-
9 test/intltest/ustrtest.cpp | 62 +++++++++++++++++++++++++
10 test/intltest/ustrtest.h | 1 +
11 3 files changed, 68 insertions(+), 1 deletion(-)
13 diff --git a/common/unistr.cpp b/common/unistr.cpp
14 index 901bb3358ba..077b4d6ef20 100644
15 --- a/common/unistr.cpp
16 +++ b/common/unistr.cpp
17 @@ -1563,7 +1563,11 @@ UnicodeString::doAppend(const UChar *srcChars, int32_t srcStart, int32_t srcLeng
20 int32_t oldLength = length();
21 - int32_t newLength = oldLength + srcLength;
23 + if (uprv_add32_overflow(oldLength, srcLength, &newLength)) {
28 // Check for append onto ourself
29 const UChar* oldArray = getArrayStart();
30 diff --git a/test/intltest/ustrtest.cpp b/test/intltest/ustrtest.cpp
31 index b6515ea813c..ad38bdf53a3 100644
32 --- a/test/intltest/ustrtest.cpp
33 +++ b/test/intltest/ustrtest.cpp
34 @@ -67,6 +67,7 @@ void UnicodeStringTest::runIndexedTest( int32_t index, UBool exec, const char* &
35 TESTCASE_AUTO(TestWCharPointers);
36 TESTCASE_AUTO(TestNullPointers);
37 TESTCASE_AUTO(TestUnicodeStringInsertAppendToSelf);
38 + TESTCASE_AUTO(TestLargeAppend);
42 @@ -2310,3 +2311,64 @@ void UnicodeStringTest::TestUnicodeStringInsertAppendToSelf() {
44 assertEquals("", u"abbcdcde", str);
47 +void UnicodeStringTest::TestLargeAppend() {
50 + IcuTestErrorCode status(*this, "TestLargeAppend");
51 + // Make a large UnicodeString
52 + int32_t len = 0xAFFFFFF;
54 + char16_t *buf = str.getBuffer(len);
55 + // A fast way to set buffer to valid Unicode.
56 + // 4E4E is a valid unicode character
57 + uprv_memset(buf, 0x4e, len * 2);
58 + str.releaseBuffer(len);
60 + // Append it 16 times
61 + // 0xAFFFFFF times 16 is 0xA4FFFFF1,
62 + // which is greater than INT32_MAX, which is 0x7FFFFFFF.
64 + for (int32_t i = 0; i < 16; i++) {
67 + if (total <= INT32_MAX) {
68 + assertFalse("dest is not bogus", dest.isBogus());
70 + assertTrue("dest should be bogus", dest.isBogus());
75 + for (int32_t i = 0; i < 16; i++) {
78 + if (total + len <= INT32_MAX) {
79 + assertFalse("dest is not bogus", dest.isBogus());
80 + } else if (total <= INT32_MAX) {
81 + // Check that a string of exactly the maximum size works
83 + int32_t remain = INT32_MAX - total;
84 + char16_t *buf2 = str2.getBuffer(remain);
85 + if (buf2 == nullptr) {
86 + // if somehow memory allocation fail, return the test
89 + uprv_memset(buf2, 0x4e, remain * 2);
90 + str2.releaseBuffer(remain);
93 + assertEquals("When a string of exactly the maximum size works", (int64_t)INT32_MAX, total);
94 + assertEquals("When a string of exactly the maximum size works", INT32_MAX, dest.length());
95 + assertFalse("dest is not bogus", dest.isBogus());
97 + // Check that a string size+1 goes bogus
101 + assertTrue("dest should be bogus", dest.isBogus());
103 + assertTrue("dest should be bogus", dest.isBogus());
107 diff --git a/test/intltest/ustrtest.h b/test/intltest/ustrtest.h
108 index 218befdcc68..4a356a92c7a 100644
109 --- a/test/intltest/ustrtest.h
110 +++ b/test/intltest/ustrtest.h
111 @@ -97,6 +97,7 @@ class UnicodeStringTest: public IntlTest {
112 void TestWCharPointers();
113 void TestNullPointers();
114 void TestUnicodeStringInsertAppendToSelf();
115 + void TestLargeAppend();