icu-65.1-prevent-SEGV_MAPERR-in-append.patch 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  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
  5. See #971
  6. ---
  7. icu4c/source/common/unistr.cpp | 6 ++-
  8. icu4c/source/test/intltest/ustrtest.cpp | 62 +++++++++++++++++++++++++
  9. icu4c/source/test/intltest/ustrtest.h | 1 +
  10. 3 files changed, 68 insertions(+), 1 deletion(-)
  11. diff --git a/icu4c/source/common/unistr.cpp b/icu4c/source/common/unistr.cpp
  12. index 901bb3358ba..077b4d6ef20 100644
  13. --- a/icu4c/source/common/unistr.cpp
  14. +++ b/icu4c/source/common/unistr.cpp
  15. @@ -1563,7 +1563,11 @@ UnicodeString::doAppend(const UChar *srcChars, int32_t srcStart, int32_t srcLeng
  16. }
  17. int32_t oldLength = length();
  18. - int32_t newLength = oldLength + srcLength;
  19. + int32_t newLength;
  20. + if (uprv_add32_overflow(oldLength, srcLength, &newLength)) {
  21. + setToBogus();
  22. + return *this;
  23. + }
  24. // Check for append onto ourself
  25. const UChar* oldArray = getArrayStart();
  26. diff --git a/icu4c/source/test/intltest/ustrtest.cpp b/icu4c/source/test/intltest/ustrtest.cpp
  27. index b6515ea813c..ad38bdf53a3 100644
  28. --- a/icu4c/source/test/intltest/ustrtest.cpp
  29. +++ b/icu4c/source/test/intltest/ustrtest.cpp
  30. @@ -67,6 +67,7 @@ void UnicodeStringTest::runIndexedTest( int32_t index, UBool exec, const char* &
  31. TESTCASE_AUTO(TestWCharPointers);
  32. TESTCASE_AUTO(TestNullPointers);
  33. TESTCASE_AUTO(TestUnicodeStringInsertAppendToSelf);
  34. + TESTCASE_AUTO(TestLargeAppend);
  35. TESTCASE_AUTO_END;
  36. }
  37. @@ -2310,3 +2311,64 @@ void UnicodeStringTest::TestUnicodeStringInsertAppendToSelf() {
  38. str.insert(2, sub);
  39. assertEquals("", u"abbcdcde", str);
  40. }
  41. +
  42. +void UnicodeStringTest::TestLargeAppend() {
  43. + if(quick) return;
  44. +
  45. + IcuTestErrorCode status(*this, "TestLargeAppend");
  46. + // Make a large UnicodeString
  47. + int32_t len = 0xAFFFFFF;
  48. + UnicodeString str;
  49. + char16_t *buf = str.getBuffer(len);
  50. + // A fast way to set buffer to valid Unicode.
  51. + // 4E4E is a valid unicode character
  52. + uprv_memset(buf, 0x4e, len * 2);
  53. + str.releaseBuffer(len);
  54. + UnicodeString dest;
  55. + // Append it 16 times
  56. + // 0xAFFFFFF times 16 is 0xA4FFFFF1,
  57. + // which is greater than INT32_MAX, which is 0x7FFFFFFF.
  58. + int64_t total = 0;
  59. + for (int32_t i = 0; i < 16; i++) {
  60. + dest.append(str);
  61. + total += len;
  62. + if (total <= INT32_MAX) {
  63. + assertFalse("dest is not bogus", dest.isBogus());
  64. + } else {
  65. + assertTrue("dest should be bogus", dest.isBogus());
  66. + }
  67. + }
  68. + dest.remove();
  69. + total = 0;
  70. + for (int32_t i = 0; i < 16; i++) {
  71. + dest.append(str);
  72. + total += len;
  73. + if (total + len <= INT32_MAX) {
  74. + assertFalse("dest is not bogus", dest.isBogus());
  75. + } else if (total <= INT32_MAX) {
  76. + // Check that a string of exactly the maximum size works
  77. + UnicodeString str2;
  78. + int32_t remain = INT32_MAX - total;
  79. + char16_t *buf2 = str2.getBuffer(remain);
  80. + if (buf2 == nullptr) {
  81. + // if somehow memory allocation fail, return the test
  82. + return;
  83. + }
  84. + uprv_memset(buf2, 0x4e, remain * 2);
  85. + str2.releaseBuffer(remain);
  86. + dest.append(str2);
  87. + total += remain;
  88. + assertEquals("When a string of exactly the maximum size works", (int64_t)INT32_MAX, total);
  89. + assertEquals("When a string of exactly the maximum size works", INT32_MAX, dest.length());
  90. + assertFalse("dest is not bogus", dest.isBogus());
  91. +
  92. + // Check that a string size+1 goes bogus
  93. + str2.truncate(1);
  94. + dest.append(str2);
  95. + total++;
  96. + assertTrue("dest should be bogus", dest.isBogus());
  97. + } else {
  98. + assertTrue("dest should be bogus", dest.isBogus());
  99. + }
  100. + }
  101. +}
  102. diff --git a/icu4c/source/test/intltest/ustrtest.h b/icu4c/source/test/intltest/ustrtest.h
  103. index 218befdcc68..4a356a92c7a 100644
  104. --- a/icu4c/source/test/intltest/ustrtest.h
  105. +++ b/icu4c/source/test/intltest/ustrtest.h
  106. @@ -97,6 +97,7 @@ class UnicodeStringTest: public IntlTest {
  107. void TestWCharPointers();
  108. void TestNullPointers();
  109. void TestUnicodeStringInsertAppendToSelf();
  110. + void TestLargeAppend();
  111. };
  112. #endif