From 90b6b640241999cf6b9ba7090c0aa96c020f872b Mon Sep 17 00:00:00 2001 From: Markus Scherer Date: Fri, 10 Jan 2014 23:14:14 +0000 Subject: [PATCH] ICU-10561 ZoneMeta methods must check for bogus input strings X-SVN-Rev: 34873 --- icu4c/source/i18n/timezone.cpp | 9 ++++++++- icu4c/source/i18n/unicode/timezone.h | 6 +++--- icu4c/source/i18n/unicode/tzfmt.h | 6 +++--- icu4c/source/i18n/unicode/tznames.h | 10 ++++----- icu4c/source/i18n/unicode/ucal.h | 4 ++-- icu4c/source/i18n/zonemeta.cpp | 16 +++++++-------- icu4c/source/test/intltest/tztest.cpp | 29 +++++++++++++++++++++++++++ icu4c/source/test/intltest/tztest.h | 3 ++- 8 files changed, 59 insertions(+), 24 deletions(-) diff --git a/icu4c/source/i18n/timezone.cpp b/icu4c/source/i18n/timezone.cpp index e656a7a8b90..6ed008df614 100644 --- a/icu4c/source/i18n/timezone.cpp +++ b/icu4c/source/i18n/timezone.cpp @@ -1,6 +1,6 @@ /* ******************************************************************************* -* Copyright (C) 1997-2013, International Business Machines Corporation and +* Copyright (C) 1997-2014, International Business Machines Corporation and * others. All Rights Reserved. ******************************************************************************* * @@ -1293,6 +1293,8 @@ TimeZone::getCustomID(const UnicodeString& id, UnicodeString& normalized, UError int32_t sign, hour, min, sec; if (parseCustomID(id, sign, hour, min, sec)) { formatCustomID(hour, min, sec, (sign < 0), normalized); + } else { + status = U_ILLEGAL_ARGUMENT_ERROR; } return normalized; } @@ -1538,6 +1540,11 @@ TimeZone::getWindowsID(const UnicodeString& id, UnicodeString& winid, UErrorCode getCanonicalID(id, canonicalID, isSystemID, status); if (U_FAILURE(status) || !isSystemID) { // mapping data is only applicable to tz database IDs + if (status == U_ILLEGAL_ARGUMENT_ERROR) { + // getWindowsID() sets an empty string where + // getCanonicalID() sets a U_ILLEGAL_ARGUMENT_ERROR. + status = U_ZERO_ERROR; + } return winid; } diff --git a/icu4c/source/i18n/unicode/timezone.h b/icu4c/source/i18n/unicode/timezone.h index 6be60e07108..6490879f792 100644 --- a/icu4c/source/i18n/unicode/timezone.h +++ b/icu4c/source/i18n/unicode/timezone.h @@ -1,5 +1,5 @@ /************************************************************************* -* Copyright (c) 1997-2013, International Business Machines Corporation +* Copyright (c) 1997-2014, International Business Machines Corporation * and others. All Rights Reserved. ************************************************************************** * @@ -330,7 +330,7 @@ public: * @param id The input time zone ID to be canonicalized. * @param canonicalID Receives the canonical system time zone ID * or the custom time zone ID in normalized format. - * @param status Recevies the status. When the given time zone ID + * @param status Receives the status. When the given time zone ID * is neither a known system time zone ID nor a * valid custom time zone ID, U_ILLEGAL_ARGUMENT_ERROR * is set. @@ -348,7 +348,7 @@ public: * or the custom time zone ID in normalized format. * @param isSystemID Receives if the given ID is a known system * time zone ID. - * @param status Recevies the status. When the given time zone ID + * @param status Receives the status. When the given time zone ID * is neither a known system time zone ID nor a * valid custom time zone ID, U_ILLEGAL_ARGUMENT_ERROR * is set. diff --git a/icu4c/source/i18n/unicode/tzfmt.h b/icu4c/source/i18n/unicode/tzfmt.h index fa8e8d64442..cb1006deae3 100644 --- a/icu4c/source/i18n/unicode/tzfmt.h +++ b/icu4c/source/i18n/unicode/tzfmt.h @@ -1,7 +1,7 @@ /* ******************************************************************************* -* Copyright (C) 2011-2013, International Business Machines Corporation and * -* others. All Rights Reserved. * +* Copyright (C) 2011-2014, International Business Machines Corporation and +* others. All Rights Reserved. ******************************************************************************* */ #ifndef __TZFMT_H @@ -302,7 +302,7 @@ public: /** * Creates an instance of TimeZoneFormat for the given locale. * @param locale The locale. - * @param status Recevies the status. + * @param status Receives the status. * @return An instance of TimeZoneFormat for the given locale, * owned by the caller. * @stable ICU 50 diff --git a/icu4c/source/i18n/unicode/tznames.h b/icu4c/source/i18n/unicode/tznames.h index 78669d466b4..acd40f4a94d 100644 --- a/icu4c/source/i18n/unicode/tznames.h +++ b/icu4c/source/i18n/unicode/tznames.h @@ -1,7 +1,7 @@ /* ******************************************************************************* -* Copyright (C) 2011-2013, International Business Machines Corporation and * -* others. All Rights Reserved. * +* Copyright (C) 2011-2014, International Business Machines Corporation and +* others. All Rights Reserved. ******************************************************************************* */ #ifndef __TZNAMES_H @@ -163,7 +163,7 @@ public: * Returns an instance of TimeZoneDisplayNames for the specified locale. * * @param locale The locale. - * @param status Recevies the status. + * @param status Receives the status. * @return An instance of TimeZoneDisplayNames * @stable ICU 50 */ @@ -171,7 +171,7 @@ public: /** * Returns an enumeration of all available meta zone IDs. - * @param status Recevies the status. + * @param status Receives the status. * @return an enumeration object, owned by the caller. * @stable ICU 50 */ @@ -180,7 +180,7 @@ public: /** * Returns an enumeration of all available meta zone IDs used by the given time zone. * @param tzID The canoical tiem zone ID. - * @param status Recevies the status. + * @param status Receives the status. * @return an enumeration object, owned by the caller. * @stable ICU 50 */ diff --git a/icu4c/source/i18n/unicode/ucal.h b/icu4c/source/i18n/unicode/ucal.h index 8f0cccc4513..276e49af04e 100644 --- a/icu4c/source/i18n/unicode/ucal.h +++ b/icu4c/source/i18n/unicode/ucal.h @@ -1,6 +1,6 @@ /* ******************************************************************************* - * Copyright (C) 1996-2013, International Business Machines Corporation and + * Copyright (C) 1996-2014, International Business Machines Corporation and * others. All Rights Reserved. ******************************************************************************* */ @@ -1289,7 +1289,7 @@ ucal_getTZDataVersion(UErrorCode* status); * @param resultCapacity The capacity of the result buffer. * @param isSystemID Receives if the given ID is a known system * timezone ID. - * @param status Recevies the status. When the given timezone ID + * @param status Receives the status. When the given timezone ID * is neither a known system time zone ID nor a * valid custom timezone ID, U_ILLEGAL_ARGUMENT_ERROR * is set. diff --git a/icu4c/source/i18n/zonemeta.cpp b/icu4c/source/i18n/zonemeta.cpp index 1d34af5a9b7..be71a3b4fd9 100644 --- a/icu4c/source/i18n/zonemeta.cpp +++ b/icu4c/source/i18n/zonemeta.cpp @@ -1,6 +1,6 @@ /* ******************************************************************************* -* Copyright (C) 2007-2013, International Business Machines Corporation and +* Copyright (C) 2007-2014, International Business Machines Corporation and * others. All Rights Reserved. ******************************************************************************* */ @@ -27,6 +27,8 @@ #include "uhash.h" #include "olsontz.h" +#define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0])) + static UMutex gZoneMetaLock = U_MUTEX_INITIALIZER; // CLDR Canonical ID mapping table @@ -235,8 +237,7 @@ ZoneMeta::getCanonicalCLDRID(const UnicodeString &tzid, UErrorCode& status) { return NULL; } - int32_t len = tzid.length(); - if (len > ZID_KEY_MAX) { + if (tzid.isBogus() || tzid.length() > ZID_KEY_MAX) { status = U_ILLEGAL_ARGUMENT_ERROR; return NULL; } @@ -268,10 +269,7 @@ ZoneMeta::getCanonicalCLDRID(const UnicodeString &tzid, UErrorCode& status) { // If not, resolve CLDR canonical ID with resource data UBool isInputCanonical = FALSE; char id[ZID_KEY_MAX + 1]; - const UChar* idChars = tzid.getBuffer(); - - u_UCharsToChars(idChars,id,len); - id[len] = (char) 0; // Make sure it is null terminated. + tzid.extract(0, 0x7fffffff, id, LENGTHOF(id), US_INV); // replace '/' with ':' char *p = id; @@ -309,7 +307,7 @@ ZoneMeta::getCanonicalCLDRID(const UnicodeString &tzid, UErrorCode& status) { if (derefer == NULL) { status = U_ILLEGAL_ARGUMENT_ERROR; } else { - len = u_strlen(derefer); + int32_t len = u_strlen(derefer); u_UCharsToChars(derefer,id,len); id[len] = (char) 0; // Make sure it is null terminated. @@ -717,7 +715,7 @@ ZoneMeta::getZoneIdByMetazone(const UnicodeString &mzid, const UnicodeString &re char keyBuf[ZID_KEY_MAX + 1]; int32_t keyLen = 0; - if (mzid.length() > ZID_KEY_MAX) { + if (mzid.isBogus() || mzid.length() > ZID_KEY_MAX) { result.setToBogus(); return result; } diff --git a/icu4c/source/test/intltest/tztest.cpp b/icu4c/source/test/intltest/tztest.cpp index af4a570bdcc..dc25974e79c 100644 --- a/icu4c/source/test/intltest/tztest.cpp +++ b/icu4c/source/test/intltest/tztest.cpp @@ -66,6 +66,7 @@ void TimeZoneTest::runIndexedTest( int32_t index, UBool exec, const char* &name, TESTCASE_AUTO(TestAliasedNames); TESTCASE_AUTO(TestFractionalDST); TESTCASE_AUTO(TestFebruary); + TESTCASE_AUTO(TestCanonicalIDAPI); TESTCASE_AUTO(TestCanonicalID); TESTCASE_AUTO(TestDisplayNamesMeta); TESTCASE_AUTO(TestGetRegion); @@ -1938,6 +1939,34 @@ void TimeZoneTest::TestFebruary() { } } } + +void TimeZoneTest::TestCanonicalIDAPI() { + // Bogus input string. + UnicodeString bogus; + bogus.setToBogus(); + UnicodeString canonicalID; + UErrorCode ec = U_ZERO_ERROR; + UnicodeString *pResult = &TimeZone::getCanonicalID(bogus, canonicalID, ec); + assertEquals("TimeZone::getCanonicalID(bogus) should fail", U_ILLEGAL_ARGUMENT_ERROR, ec); + assertTrue("TimeZone::getCanonicalID(bogus) should return the dest string", pResult == &canonicalID); + + // U_FAILURE on input. + UnicodeString berlin("Europe/Berlin"); + ec = U_MEMORY_ALLOCATION_ERROR; + pResult = &TimeZone::getCanonicalID(berlin, canonicalID, ec); + assertEquals("TimeZone::getCanonicalID(failure) should fail", U_MEMORY_ALLOCATION_ERROR, ec); + assertTrue("TimeZone::getCanonicalID(failure) should return the dest string", pResult == &canonicalID); + + // Valid input should un-bogus the dest string. + canonicalID.setToBogus(); + ec = U_ZERO_ERROR; + pResult = &TimeZone::getCanonicalID(berlin, canonicalID, ec); + assertSuccess("TimeZone::getCanonicalID(bogus dest) should succeed", ec); + assertTrue("TimeZone::getCanonicalID(bogus dest) should return the dest string", pResult == &canonicalID); + assertFalse("TimeZone::getCanonicalID(bogus dest) should un-bogus the dest string", canonicalID.isBogus()); + assertEquals("TimeZone::getCanonicalID(bogus dest) unexpected result", canonicalID, berlin); +} + void TimeZoneTest::TestCanonicalID() { // Some canonical IDs in CLDR are defined as "Link" diff --git a/icu4c/source/test/intltest/tztest.h b/icu4c/source/test/intltest/tztest.h index 0fbe93fb6a8..f1737ca794f 100644 --- a/icu4c/source/test/intltest/tztest.h +++ b/icu4c/source/test/intltest/tztest.h @@ -1,6 +1,6 @@ /******************************************************************** - * Copyright (c) 1997-2013, International Business Machines + * Copyright (c) 1997-2014, International Business Machines * Corporation and others. All Rights Reserved. ********************************************************************/ @@ -90,6 +90,7 @@ public: void TestFebruary(void); + void TestCanonicalIDAPI(); void TestCanonicalID(void); virtual void TestDisplayNamesMeta();