Skip to content

Commit b7d08bc

Browse files
committed
ICU-20958 Prevent SEGV_MAPERR in append
See #971
1 parent 54a60fe commit b7d08bc

File tree

3 files changed

+68
-1
lines changed

3 files changed

+68
-1
lines changed

Diff for: icu4c/source/common/unistr.cpp

+5-1
Original file line numberDiff line numberDiff line change
@@ -1563,7 +1563,11 @@ UnicodeString::doAppend(const UChar *srcChars, int32_t srcStart, int32_t srcLeng
15631563
}
15641564

15651565
int32_t oldLength = length();
1566-
int32_t newLength = oldLength + srcLength;
1566+
int32_t newLength;
1567+
if (uprv_add32_overflow(oldLength, srcLength, &newLength)) {
1568+
setToBogus();
1569+
return *this;
1570+
}
15671571

15681572
// Check for append onto ourself
15691573
const UChar* oldArray = getArrayStart();

Diff for: icu4c/source/test/intltest/ustrtest.cpp

+62
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ void UnicodeStringTest::runIndexedTest( int32_t index, UBool exec, const char* &
6767
TESTCASE_AUTO(TestWCharPointers);
6868
TESTCASE_AUTO(TestNullPointers);
6969
TESTCASE_AUTO(TestUnicodeStringInsertAppendToSelf);
70+
TESTCASE_AUTO(TestLargeAppend);
7071
TESTCASE_AUTO_END;
7172
}
7273

@@ -2310,3 +2311,64 @@ void UnicodeStringTest::TestUnicodeStringInsertAppendToSelf() {
23102311
str.insert(2, sub);
23112312
assertEquals("", u"abbcdcde", str);
23122313
}
2314+
2315+
void UnicodeStringTest::TestLargeAppend() {
2316+
if(quick) return;
2317+
2318+
IcuTestErrorCode status(*this, "TestLargeAppend");
2319+
// Make a large UnicodeString
2320+
int32_t len = 0xAFFFFFF;
2321+
UnicodeString str;
2322+
char16_t *buf = str.getBuffer(len);
2323+
// A fast way to set buffer to valid Unicode.
2324+
// 4E4E is a valid unicode character
2325+
uprv_memset(buf, 0x4e, len * 2);
2326+
str.releaseBuffer(len);
2327+
UnicodeString dest;
2328+
// Append it 16 times
2329+
// 0xAFFFFFF times 16 is 0xA4FFFFF1,
2330+
// which is greater than INT32_MAX, which is 0x7FFFFFFF.
2331+
int64_t total = 0;
2332+
for (int32_t i = 0; i < 16; i++) {
2333+
dest.append(str);
2334+
total += len;
2335+
if (total <= INT32_MAX) {
2336+
assertFalse("dest is not bogus", dest.isBogus());
2337+
} else {
2338+
assertTrue("dest should be bogus", dest.isBogus());
2339+
}
2340+
}
2341+
dest.remove();
2342+
total = 0;
2343+
for (int32_t i = 0; i < 16; i++) {
2344+
dest.append(str);
2345+
total += len;
2346+
if (total + len <= INT32_MAX) {
2347+
assertFalse("dest is not bogus", dest.isBogus());
2348+
} else if (total <= INT32_MAX) {
2349+
// Check that a string of exactly the maximum size works
2350+
UnicodeString str2;
2351+
int32_t remain = INT32_MAX - total;
2352+
char16_t *buf2 = str2.getBuffer(remain);
2353+
if (buf2 == nullptr) {
2354+
// if somehow memory allocation fail, return the test
2355+
return;
2356+
}
2357+
uprv_memset(buf2, 0x4e, remain * 2);
2358+
str2.releaseBuffer(remain);
2359+
dest.append(str2);
2360+
total += remain;
2361+
assertEquals("When a string of exactly the maximum size works", (int64_t)INT32_MAX, total);
2362+
assertEquals("When a string of exactly the maximum size works", INT32_MAX, dest.length());
2363+
assertFalse("dest is not bogus", dest.isBogus());
2364+
2365+
// Check that a string size+1 goes bogus
2366+
str2.truncate(1);
2367+
dest.append(str2);
2368+
total++;
2369+
assertTrue("dest should be bogus", dest.isBogus());
2370+
} else {
2371+
assertTrue("dest should be bogus", dest.isBogus());
2372+
}
2373+
}
2374+
}

Diff for: icu4c/source/test/intltest/ustrtest.h

+1
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ class UnicodeStringTest: public IntlTest {
9797
void TestWCharPointers();
9898
void TestNullPointers();
9999
void TestUnicodeStringInsertAppendToSelf();
100+
void TestLargeAppend();
100101
};
101102

102103
#endif

0 commit comments

Comments
 (0)