diff --git a/source/common/unistr.cpp b/source/common/unistr.cpp index 04f01cfa..626f8886 100644 --- a/source/common/unistr.cpp +++ b/source/common/unistr.cpp @@ -1865,6 +1865,13 @@ UnicodeString::cloneArrayIfNeeded(int32_t newCapacity, growCapacity = newCapacity; } else if(newCapacity <= US_STACKBUF_SIZE && growCapacity > US_STACKBUF_SIZE) { growCapacity = US_STACKBUF_SIZE; + } else if(newCapacity > growCapacity) { + setToBogus(); + return false; // bad inputs + } + if(growCapacity > kMaxCapacity) { + setToBogus(); + return false; } // save old values diff --git a/source/test/intltest/ustrtest.cpp b/source/test/intltest/ustrtest.cpp index 26c51b9c..71ebde4b 100644 --- a/source/test/intltest/ustrtest.cpp +++ b/source/test/intltest/ustrtest.cpp @@ -68,6 +68,7 @@ void UnicodeStringTest::runIndexedTest( int32_t index, UBool exec, const char* & TESTCASE_AUTO(TestNullPointers); TESTCASE_AUTO(TestUnicodeStringInsertAppendToSelf); TESTCASE_AUTO(TestLargeAppend); + TESTCASE_AUTO(TestLargeMemory); TESTCASE_AUTO_END; } @@ -2328,6 +2329,18 @@ void UnicodeStringTest::TestUnicodeStringInsertAppendToSelf() { assertEquals("", u"abbcdcde", str); } +void UnicodeStringTest::TestLargeMemory() { +#if U_PLATFORM_IS_LINUX_BASED || U_PLATFORM_IS_DARWIN_BASED + if(quick) { return; } + IcuTestErrorCode status(*this, "TestLargeMemory"); + constexpr uint32_t len = 2147483643; + char16_t *buf = new char16_t[len]; + if (buf == nullptr) { return; } + uprv_memset(buf, 0x4e, len * 2); + icu::UnicodeString test(buf, len); + delete [] buf; +#endif +} void UnicodeStringTest::TestLargeAppend() { if(quick) return; @@ -2356,15 +2369,17 @@ void UnicodeStringTest::TestLargeAppend() { } dest.remove(); total = 0; + // Copy kMaxCapacity from common/unistr.cpp + const int32_t kMaxCapacity = 0x7ffffff5; for (int32_t i = 0; i < 16; i++) { dest.append(str); total += len; - if (total + len <= INT32_MAX) { + if (total + len <= kMaxCapacity) { assertFalse("dest is not bogus", dest.isBogus()); - } else if (total <= INT32_MAX) { + } else if (total <= kMaxCapacity) { // Check that a string of exactly the maximum size works UnicodeString str2; - int32_t remain = static_cast(INT32_MAX - total); + int32_t remain = static_cast(kMaxCapacity - total); char16_t *buf2 = str2.getBuffer(remain); if (buf2 == nullptr) { // if somehow memory allocation fail, return the test @@ -2374,14 +2389,19 @@ void UnicodeStringTest::TestLargeAppend() { str2.releaseBuffer(remain); dest.append(str2); total += remain; - assertEquals("When a string of exactly the maximum size works", (int64_t)INT32_MAX, total); - assertEquals("When a string of exactly the maximum size works", INT32_MAX, dest.length()); + assertEquals("When a string of exactly the maximum size works", static_cast(kMaxCapacity), total); + assertEquals("When a string of exactly the maximum size works", kMaxCapacity, dest.length()); assertFalse("dest is not bogus", dest.isBogus()); - // Check that a string size+1 goes bogus + // Check that a string size+1 does not go bogus (one more byte reserved for NUL) str2.truncate(1); dest.append(str2); total++; + assertFalse("dest should be not bogus", dest.isBogus()); + // Check that a string size+2 goes bogus (beyond the byte reserved + // for NUL) + dest.append(str2); + total++; assertTrue("dest should be bogus", dest.isBogus()); } else { assertTrue("dest should be bogus", dest.isBogus()); diff --git a/source/test/intltest/ustrtest.h b/source/test/intltest/ustrtest.h index 088b7139..9e50d365 100644 --- a/source/test/intltest/ustrtest.h +++ b/source/test/intltest/ustrtest.h @@ -92,6 +92,7 @@ public: void TestUnicodeStringImplementsAppendable(); void TestSizeofUnicodeString(); void TestMoveSwap(); + void TestLargeMemory(); void TestUInt16Pointers(); void TestWCharPointers();