]> granicus.if.org Git - icu/commitdiff
ICU-12810 Prevent assertion triggered by time zone id including characters other...
authorYoshito Umaoka <y.umaoka@gmail.com>
Tue, 14 Mar 2017 19:39:30 +0000 (19:39 +0000)
committerYoshito Umaoka <y.umaoka@gmail.com>
Tue, 14 Mar 2017 19:39:30 +0000 (19:39 +0000)
X-SVN-Rev: 39799

icu4c/source/i18n/zonemeta.cpp
icu4c/source/i18n/zonemeta.h
icu4c/source/test/intltest/tzfmttst.cpp
icu4c/source/test/intltest/tzfmttst.h

index b80ac3ea379945739d480ca473a23287ddae999c..84a965780291c9de458f4931c19f960ba18380ad 100644 (file)
@@ -28,6 +28,7 @@
 #include "uresimp.h"
 #include "uhash.h"
 #include "olsontz.h"
+#include "uinvchar.h"
 
 static UMutex gZoneMetaLock = U_MUTEX_INITIALIZER;
 
@@ -255,6 +256,12 @@ ZoneMeta::getCanonicalCLDRID(const UnicodeString &tzid, UErrorCode& status) {
     tzid.extract(utzid, ZID_KEY_MAX + 1, tmpStatus);
     U_ASSERT(tmpStatus == U_ZERO_ERROR);    // we checked the length of tzid already
 
+    if (!uprv_isInvariantUString(utzid, -1)) {
+        // All of known tz IDs are only containing ASCII invariant characters.
+        status = U_ILLEGAL_ARGUMENT_ERROR;
+        return NULL;
+    }
+
     // Check if it was already cached
     umtx_lock(&gZoneMetaLock);
     {
index e0f22b779ed5f007a9fd6b45cb820d9b7df8f8bd..9dbcc878a22dc8f5537e814e01612fc221c8e0f1 100644 (file)
@@ -41,7 +41,11 @@ public:
     /**
      * Return the canonical id for this tzid defined by CLDR, which might be the id itself.
      * This overload method returns a persistent const UChar*, which is guranteed to persist
-     * (a pointer to a resource).
+     * (a pointer to a resource). If the given system tzid is not known, U_ILLEGAL_ARGUMENT_ERROR
+     * is set in the status.
+     * @param tzid Zone ID
+     * @param status Receives the status
+     * @return The canonical ID for the input time zone ID
      */
     static const UChar* U_EXPORT2 getCanonicalCLDRID(const UnicodeString &tzid, UErrorCode& status);
 
index b0d9dd5212da4328c443b87fd4b1bb3e422c19b9..e673d0aa4aee96407b2c934fc38d7bc56c24ebf4 100644 (file)
@@ -82,6 +82,7 @@ TimeZoneFormatTest::runIndexedTest( int32_t index, UBool exec, const char* &name
         TESTCASE(3, TestISOFormat);
         TESTCASE(4, TestFormat);
         TESTCASE(5, TestFormatTZDBNames);
+        TESTCASE(6, TestFormatCustomZone);
         default: name = ""; break;
     }
 }
@@ -1213,5 +1214,38 @@ TimeZoneFormatTest::TestFormatTZDBNames(void) {
     }
 }
 
+void
+TimeZoneFormatTest::TestFormatCustomZone(void) {
+    struct {
+        const char* id;
+        int32_t offset;
+        const char* expected;
+    } TESTDATA[] = {
+        { "abc", 3600000, "GMT+01:00" },                    // unknown ID
+        { "$abc", -3600000, "GMT-01:00" },                 // unknown, with ASCII variant char '$'
+        { "\\u00c1\\u00df\\u00c7", 5400000, "GMT+01:30"},    // unknown, with non-ASCII chars
+        { 0, 0, 0 }
+    };
+
+    UDate now = Calendar::getNow();
+
+    for (int32_t i = 0; ; i++) {
+        const char *id = TESTDATA[i].id;
+        if (id == 0) {
+            break;
+        }
+        UnicodeString tzid = UnicodeString(id, -1, US_INV).unescape();
+        SimpleTimeZone tz(TESTDATA[i].offset, tzid);
+
+        UErrorCode status = U_ZERO_ERROR;
+        LocalPointer<TimeZoneFormat> tzfmt(TimeZoneFormat::createInstance(Locale("en"), status));
+        UnicodeString tzstr;
+        UnicodeString expected = UnicodeString(TESTDATA[i].expected, -1, US_INV).unescape();
+
+        tzfmt->format(UTZFMT_STYLE_SPECIFIC_LONG, tz, now, tzstr, NULL);
+        assertEquals(UnicodeString("Format result for ") + tzid, expected, tzstr);
+    }
+}
+
 
 #endif /* #if !UCONFIG_NO_FORMATTING */
index 9e70f117da2416014fdd34b0954b26d9cccf90c7..0bf91ae0e8ea5d10affe26172ed40822a71a07f6 100644 (file)
@@ -27,6 +27,7 @@ class TimeZoneFormatTest : public IntlTest {
     void TestISOFormat(void);
     void TestFormat(void);
     void TestFormatTZDBNames(void);
+    void TestFormatCustomZone(void);
 
     void RunTimeRoundTripTests(int32_t threadNumber);
 };