ICU-12810 Prevent assertion triggered by time zone id including characters other than ASCII invariants initialize/formatting a time zone.

X-SVN-Rev: 39799
This commit is contained in:
Yoshito Umaoka 2017-03-14 19:39:30 +00:00
parent 9b50ba1c2e
commit f54d25d286
4 changed files with 47 additions and 1 deletions

View 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);
{

View 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);

View 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 */

View 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);
};