]> granicus.if.org Git - icu/commitdiff
ICU-12832 UTF-8 case mapping appendUChar() write a character even if it fills destCap...
authorMarkus Scherer <markus.icu@gmail.com>
Mon, 7 Nov 2016 23:15:47 +0000 (23:15 +0000)
committerMarkus Scherer <markus.icu@gmail.com>
Mon, 7 Nov 2016 23:15:47 +0000 (23:15 +0000)
X-SVN-Rev: 39500

icu4c/source/common/ucasemap.cpp
icu4c/source/test/intltest/strcase.cpp

index c0d56c28731d1f4825bcb06ebe250dcba53294a7..4d59f7d8f7bfebb077c685ad9ed43d5aece1fec3 100644 (file)
@@ -200,7 +200,7 @@ appendUChar(uint8_t *dest, int32_t destIndex, int32_t destCapacity, UChar c) {
         return -1;  // integer overflow
     }
     int32_t limit=destIndex+length;
-    if(limit<destCapacity) {
+    if(limit<=destCapacity) {
         U8_APPEND_UNSAFE(dest, destIndex, c);
     }
     return limit;
index 06665308ed68da7f5bfd0823e9e5153806bb223e..34f3e4ac22ce6c15d5ef2b3c0d8c0a531336a5e2 100644 (file)
@@ -589,6 +589,35 @@ StringCaseTest::assertGreekUpper(const char *s, const char *expected) {
     result16.toUpper(GREEK_LOCALE_);
     assertEquals(msg, expected16, result16);
 
+    msg = UnicodeString("u_strToUpper/Greek(\"") + s16 + "\") cap=";
+    int32_t length = expected16.length();
+    int32_t capacities[] = {
+        // Keep in sync with the UTF-8 capacities near the bottom of this function.
+        0, length / 2, length - 1, length, length + 1
+    };
+    for (int32_t i = 0; i < UPRV_LENGTHOF(capacities); ++i) {
+        int32_t cap = capacities[i];
+        UChar *dest16 = result16.getBuffer(expected16.length() + 1);
+        u_memset(dest16, 0x55AA, result16.getCapacity());
+        UErrorCode errorCode = U_ZERO_ERROR;
+        length = u_strToUpper(dest16, cap, s16.getBuffer(), s16.length(), "el", &errorCode);
+        assertEquals(msg + cap, expected16.length(), length);
+        UErrorCode expectedErrorCode;
+        if (cap < expected16.length()) {
+            expectedErrorCode = U_BUFFER_OVERFLOW_ERROR;
+        } else if (cap == expected16.length()) {
+            expectedErrorCode = U_STRING_NOT_TERMINATED_WARNING;
+        } else {
+            expectedErrorCode = U_ZERO_ERROR;
+            assertEquals(msg + cap + " NUL", 0, dest16[length]);
+        }
+        assertEquals(msg + cap + " errorCode", expectedErrorCode, errorCode);
+        result16.releaseBuffer(length);
+        if (cap >= expected16.length()) {
+            assertEquals(msg + cap, expected16, result16);
+        }
+    }
+
 #if U_HAVE_STD_STRING
     UErrorCode errorCode = U_ZERO_ERROR;
     LocalUCaseMapPointer csm(ucasemap_open("el", 0, &errorCode));
@@ -596,13 +625,42 @@ StringCaseTest::assertGreekUpper(const char *s, const char *expected) {
     std::string s8;
     s16.toUTF8String(s8);
     msg = UnicodeString("ucasemap_utf8ToUpper/Greek(\"") + s16 + "\")";
-    char dest[1000];
-    int32_t length = ucasemap_utf8ToUpper(csm.getAlias(), dest, UPRV_LENGTHOF(dest),
-                                          s8.data(), s8.length(), &errorCode);
+    char dest8[1000];
+    length = ucasemap_utf8ToUpper(csm.getAlias(), dest8, UPRV_LENGTHOF(dest8),
+                                  s8.data(), s8.length(), &errorCode);
     assertSuccess("ucasemap_utf8ToUpper", errorCode);
-    StringPiece result8(dest, length);
+    StringPiece result8(dest8, length);
     UnicodeString result16From8 = UnicodeString::fromUTF8(result8);
     assertEquals(msg, expected16, result16From8);
+
+    msg += " cap=";
+    capacities[1] = length / 2;
+    capacities[2] = length - 1;
+    capacities[3] = length;
+    capacities[4] = length + 1;
+    char dest8b[1000];
+    int32_t expected8Length = length;  // Assuming the previous call worked.
+    for (int32_t i = 0; i < UPRV_LENGTHOF(capacities); ++i) {
+        int32_t cap = capacities[i];
+        memset(dest8b, 0x5A, UPRV_LENGTHOF(dest8b));
+        UErrorCode errorCode = U_ZERO_ERROR;
+        length = ucasemap_utf8ToUpper(csm.getAlias(), dest8b, cap,
+                                      s8.data(), s8.length(), &errorCode);
+        assertEquals(msg + cap, expected8Length, length);
+        UErrorCode expectedErrorCode;
+        if (cap < expected8Length) {
+            expectedErrorCode = U_BUFFER_OVERFLOW_ERROR;
+        } else if (cap == expected8Length) {
+            expectedErrorCode = U_STRING_NOT_TERMINATED_WARNING;
+        } else {
+            expectedErrorCode = U_ZERO_ERROR;
+            assertEquals(msg + cap + " NUL", 0, dest8b[length]);
+        }
+        assertEquals(msg + cap + " errorCode", expectedErrorCode, errorCode);
+        if (cap >= expected8Length) {
+            assertEquals(msg + cap + " (memcmp)", 0, memcmp(dest8, dest8b, expected8Length));
+        }
+    }
 #endif
 }