From dd4971d760fc096461cebee8a389f3a6c2bec8d9 Mon Sep 17 00:00:00 2001 From: "Steven R. Loomis" Date: Sat, 14 Feb 2009 02:29:08 +0000 Subject: [PATCH] ICU-6613 fix udat crashers. See also ICU-6737 X-SVN-Rev: 25405 --- icu4c/source/i18n/udat.cpp | 36 +++++++- icu4c/source/test/cintltst/cdattst.c | 129 ++++++++++++++++++++++++--- 2 files changed, 149 insertions(+), 16 deletions(-) diff --git a/icu4c/source/i18n/udat.cpp b/icu4c/source/i18n/udat.cpp index 7834b4cbba8..f984bf82ef0 100644 --- a/icu4c/source/i18n/udat.cpp +++ b/icu4c/source/i18n/udat.cpp @@ -1,6 +1,6 @@ /* ******************************************************************************* -* Copyright (C) 1996-2006, International Business Machines +* Copyright (C) 1996-2009, International Business Machines * Corporation and others. All Rights Reserved. ******************************************************************************* */ @@ -25,6 +25,18 @@ U_NAMESPACE_USE +/** + * Verify that fmt is a SimpleDateFormat. Invalid error if not. + * @param fmt the UDateFormat, definitely a DateFormat, maybe something else + * @param status error code, will be set to failure if there is a familure or the fmt is NULL. + */ +static void verifyIsSimpleDateFormat(const UDateFormat* fmt, UErrorCode *status) { + if(!U_FAILURE(*status) && + ((DateFormat*)fmt)->getDynamicClassID()!=SimpleDateFormat::getStaticClassID()) { + *status = U_ILLEGAL_ARGUMENT_ERROR; + } +} + U_CAPI UDateFormat* U_EXPORT2 udat_open(UDateFormatStyle timeStyle, UDateFormatStyle dateStyle, @@ -92,7 +104,7 @@ udat_clone(const UDateFormat *fmt, { if(U_FAILURE(*status)) return 0; - Format *res = ((SimpleDateFormat*)fmt)->clone(); + Format *res = ((DateFormat*)fmt)->clone(); if(res == 0) { *status = U_MEMORY_ALLOCATION_ERROR; @@ -249,6 +261,7 @@ U_CAPI UDate U_EXPORT2 udat_get2DigitYearStart( const UDateFormat *fmt, UErrorCode *status) { + verifyIsSimpleDateFormat(fmt, status); if(U_FAILURE(*status)) return (UDate)0; return ((SimpleDateFormat*)fmt)->get2DigitYearStart(*status); } @@ -258,6 +271,7 @@ udat_set2DigitYearStart( UDateFormat *fmt, UDate d, UErrorCode *status) { + verifyIsSimpleDateFormat(fmt, status); if(U_FAILURE(*status)) return; ((SimpleDateFormat*)fmt)->set2DigitYearStart(d, *status); } @@ -269,6 +283,7 @@ udat_toPattern( const UDateFormat *fmt, int32_t resultLength, UErrorCode *status) { + verifyIsSimpleDateFormat(fmt, status); if(U_FAILURE(*status)) return -1; UnicodeString res; @@ -286,7 +301,8 @@ udat_toPattern( const UDateFormat *fmt, return res.extract(result, resultLength, *status); } -// TBD: should this take an UErrorCode? +// TODO: should this take an UErrorCode? +// A: Yes. Of course. U_CAPI void U_EXPORT2 udat_applyPattern( UDateFormat *format, UBool localized, @@ -296,6 +312,11 @@ udat_applyPattern( UDateFormat *format, const UnicodeString pat((UBool)(patternLength == -1), pattern, patternLength); UErrorCode status = U_ZERO_ERROR; + verifyIsSimpleDateFormat(format, &status); + if(U_FAILURE(status)) { + return; + } + if(localized) ((SimpleDateFormat*)format)->applyLocalizedPattern(pat, status); else @@ -310,6 +331,7 @@ udat_getSymbols(const UDateFormat *fmt, int32_t resultLength, UErrorCode *status) { + verifyIsSimpleDateFormat(fmt, status); if(U_FAILURE(*status)) return -1; const DateFormatSymbols *syms = @@ -414,10 +436,18 @@ udat_getSymbols(const UDateFormat *fmt, return 0; } +// TODO: also needs an errorCode. U_CAPI int32_t U_EXPORT2 udat_countSymbols( const UDateFormat *fmt, UDateFormatSymbolType type) { + UErrorCode status = U_ZERO_ERROR; + + verifyIsSimpleDateFormat(fmt, &status); + if(U_FAILURE(status)) { + return 0; + } + const DateFormatSymbols *syms = ((SimpleDateFormat*)fmt)->getDateFormatSymbols(); int32_t count = 0; diff --git a/icu4c/source/test/cintltst/cdattst.c b/icu4c/source/test/cintltst/cdattst.c index 9aa40b38575..0c9c37362f7 100644 --- a/icu4c/source/test/cintltst/cdattst.c +++ b/icu4c/source/test/cintltst/cdattst.c @@ -33,6 +33,7 @@ static void TestExtremeDates(void); static void TestAllLocales(void); +static void TestRelativeCrash(void); #define LEN(a) (sizeof(a)/sizeof(a[0])) @@ -48,6 +49,7 @@ void addDateForTest(TestNode** root) TESTCASE(TestDateFormatCalendar); TESTCASE(TestExtremeDates); TESTCASE(TestAllLocales); + TESTCASE(TestRelativeCrash); } /* Testing the DateFormat API */ static void TestDateFormat() @@ -806,7 +808,8 @@ static void TestDateFormatCalendar() { } /*INTERNAL FUNCTIONS USED*/ -static void VerifygetSymbols(UDateFormat* datfor, UDateFormatSymbolType type, int32_t index, const char* expected) +/* N.B.: use idx instead of index to avoid 'shadow' warnings in strict mode. */ +static void VerifygetSymbols(UDateFormat* datfor, UDateFormatSymbolType type, int32_t idx, const char* expected) { UChar *pattern=NULL; UErrorCode status = U_ZERO_ERROR; @@ -817,13 +820,13 @@ static void VerifygetSymbols(UDateFormat* datfor, UDateFormatSymbolType type, in pattern=(UChar*)malloc(sizeof(UChar) * (strlen(expected)+1)); u_uastrcpy(pattern, expected); resultlength=0; - resultlengthout=udat_getSymbols(datfor, type, index , NULL, resultlength, &status); + resultlengthout=udat_getSymbols(datfor, type, idx , NULL, resultlength, &status); if(status==U_BUFFER_OVERFLOW_ERROR) { status=U_ZERO_ERROR; resultlength=resultlengthout+1; result=(UChar*)malloc(sizeof(UChar) * resultlength); - udat_getSymbols(datfor, type, index, result, resultlength, &status); + udat_getSymbols(datfor, type, idx, result, resultlength, &status); } if(U_FAILURE(status)) @@ -841,7 +844,7 @@ static void VerifygetSymbols(UDateFormat* datfor, UDateFormatSymbolType type, in free(pattern); } -static void VerifysetSymbols(UDateFormat* datfor, UDateFormatSymbolType type, int32_t index, const char* expected) +static void VerifysetSymbols(UDateFormat* datfor, UDateFormatSymbolType type, int32_t idx, const char* expected) { UChar *result=NULL; UChar *value=NULL; @@ -850,7 +853,7 @@ static void VerifysetSymbols(UDateFormat* datfor, UDateFormatSymbolType type, in value=(UChar*)malloc(sizeof(UChar) * (strlen(expected) + 1)); u_uastrcpy(value, expected); - udat_setSymbols(datfor, type, index, value, u_strlen(value), &status); + udat_setSymbols(datfor, type, idx, value, u_strlen(value), &status); if(U_FAILURE(status)) { log_err("FAIL: Error in udat_setSymbols() %s\n", myErrorName(status) ); @@ -858,12 +861,12 @@ static void VerifysetSymbols(UDateFormat* datfor, UDateFormatSymbolType type, in } resultlength=0; - resultlengthout=udat_getSymbols(datfor, type, index, NULL, resultlength, &status); + resultlengthout=udat_getSymbols(datfor, type, idx, NULL, resultlength, &status); if(status==U_BUFFER_OVERFLOW_ERROR){ status=U_ZERO_ERROR; resultlength=resultlengthout+1; result=(UChar*)malloc(sizeof(UChar) * resultlength); - udat_getSymbols(datfor, type, index, result, resultlength, &status); + udat_getSymbols(datfor, type, idx, result, resultlength, &status); } if(U_FAILURE(status)){ log_err("FAIL: error in retrieving the value using getSymbols after setting it previously\n %s\n", @@ -883,7 +886,7 @@ static void VerifysetSymbols(UDateFormat* datfor, UDateFormatSymbolType type, in } -static void VerifygetsetSymbols(UDateFormat* from, UDateFormat* to, UDateFormatSymbolType type, int32_t index) +static void VerifygetsetSymbols(UDateFormat* from, UDateFormat* to, UDateFormatSymbolType type, int32_t idx) { UChar *result=NULL; UChar *value=NULL; @@ -891,12 +894,12 @@ static void VerifygetsetSymbols(UDateFormat* from, UDateFormat* to, UDateFormatS UErrorCode status = U_ZERO_ERROR; resultlength=0; - resultlengthout=udat_getSymbols(from, type, index , NULL, resultlength, &status); + resultlengthout=udat_getSymbols(from, type, idx , NULL, resultlength, &status); if(status==U_BUFFER_OVERFLOW_ERROR){ status=U_ZERO_ERROR; resultlength=resultlengthout+1; result=(UChar*)malloc(sizeof(UChar) * resultlength); - udat_getSymbols(from, type, index, result, resultlength, &status); + udat_getSymbols(from, type, idx, result, resultlength, &status); } if(U_FAILURE(status)){ log_err("FAIL: error in getSymbols() %s\n", myErrorName(status) ); @@ -904,7 +907,7 @@ static void VerifygetsetSymbols(UDateFormat* from, UDateFormat* to, UDateFormatS } resultlength=resultlengthout+1; - udat_setSymbols(to, type, index, result, resultlength, &status); + udat_setSymbols(to, type, idx, result, resultlength, &status); if(U_FAILURE(status)) { log_err("FAIL: Error in udat_setSymbols() : %s\n", myErrorName(status) ); @@ -912,12 +915,12 @@ static void VerifygetsetSymbols(UDateFormat* from, UDateFormat* to, UDateFormatS } resultlength=0; - resultlengthout=udat_getSymbols(to, type, index, NULL, resultlength, &status); + resultlengthout=udat_getSymbols(to, type, idx, NULL, resultlength, &status); if(status==U_BUFFER_OVERFLOW_ERROR){ status=U_ZERO_ERROR; resultlength=resultlengthout+1; value=(UChar*)malloc(sizeof(UChar) * resultlength); - udat_getSymbols(to, type, index, value, resultlength, &status); + udat_getSymbols(to, type, idx, value, resultlength, &status); } if(U_FAILURE(status)){ log_err("FAIL: error in retrieving the value using getSymbols i.e roundtrip\n %s\n", @@ -1064,4 +1067,104 @@ static void TestAllLocales(void) { } } +static void TestRelativeCrash(void) { + static const UChar tzName[] = { 0x0055, 0x0053, 0x002F, 0x0050, 0x0061, 0x0063, 0x0069, 0x0066, 0x0069, 0x0063, 0 }; + static const UDate aDate = -631152000000.0; + + UErrorCode status = U_ZERO_ERROR; + UErrorCode expectStatus = U_ILLEGAL_ARGUMENT_ERROR; + UDateFormat icudf; + + icudf = udat_open(UDAT_NONE, UDAT_SHORT_RELATIVE, "en", tzName, -1, NULL, 0, &status); + if ( U_SUCCESS(status) ) { + const char *what = "???"; + { + UErrorCode subStatus = U_ZERO_ERROR; + what = "udat_set2DigitYearStart"; + log_verbose("Trying %s on a relative date..\n", what); + udat_set2DigitYearStart(icudf, aDate, &subStatus); + if(subStatus == expectStatus) { + log_verbose("Success: did not crash on %s, but got %s.\n", what, u_errorName(subStatus)); + } else { + log_err("FAIL: didn't crash on %s, but got success %s instead of %s. \n", what, u_errorName(subStatus), u_errorName(expectStatus)); + } + } + { + /* clone works polymorphically. try it anyways */ + UErrorCode subStatus = U_ZERO_ERROR; + UDateFormat *oth; + what = "clone"; + log_verbose("Trying %s on a relative date..\n", what); + oth = udat_clone(icudf, &subStatus); + if(subStatus == U_ZERO_ERROR) { + log_verbose("Success: did not crash on %s, but got %s.\n", what, u_errorName(subStatus)); + udat_close(oth); /* ? */ + } else { + log_err("FAIL: didn't crash on %s, but got %s instead of %s. \n", what, u_errorName(subStatus), u_errorName(expectStatus)); + } + } + { + UErrorCode subStatus = U_ZERO_ERROR; + what = "udat_get2DigitYearStart"; + log_verbose("Trying %s on a relative date..\n", what); + udat_get2DigitYearStart(icudf, &subStatus); + if(subStatus == expectStatus) { + log_verbose("Success: did not crash on %s, but got %s.\n", what, u_errorName(subStatus)); + } else { + log_err("FAIL: didn't crash on %s, but got success %s instead of %s. \n", what, u_errorName(subStatus), u_errorName(expectStatus)); + } + } + { + UErrorCode subStatus = U_ZERO_ERROR; + what = "udat_toPattern"; + log_verbose("Trying %s on a relative date..\n", what); + udat_toPattern(icudf, FALSE,NULL,0, &subStatus); + if(subStatus == expectStatus) { + log_verbose("Success: did not crash on %s, but got %s.\n", what, u_errorName(subStatus)); + } else { + log_err("FAIL: didn't crash on %s, but got success %s instead of %s. \n", what, u_errorName(subStatus), u_errorName(expectStatus)); + } + } + { + UErrorCode subStatus = U_ZERO_ERROR; + what = "udat_applyPattern"; + log_verbose("Trying %s on a relative date..\n", what); + udat_applyPattern(icudf, FALSE,tzName,-1); + subStatus = U_ILLEGAL_ARGUMENT_ERROR; /* what it should be, if this took an errorcode. */ + if(subStatus == expectStatus) { + log_verbose("Success: did not crash on %s, but got %s.\n", what, u_errorName(subStatus)); + } else { + log_err("FAIL: didn't crash on %s, but got success %s instead of %s. \n", what, u_errorName(subStatus), u_errorName(expectStatus)); + } + } + { + UErrorCode subStatus = U_ZERO_ERROR; + what = "udat_getSymbols"; + log_verbose("Trying %s on a relative date..\n", what); + udat_getSymbols(icudf, UDAT_ERAS,0,NULL,0, &subStatus); /* bogus values */ + if(subStatus == expectStatus) { + log_verbose("Success: did not crash on %s, but got %s.\n", what, u_errorName(subStatus)); + } else { + log_err("FAIL: didn't crash on %s, but got success %s instead of %s. \n", what, u_errorName(subStatus), u_errorName(expectStatus)); + } + } + { + UErrorCode subStatus = U_ZERO_ERROR; + what = "udat_countSymbols"; + log_verbose("Trying %s on a relative date..\n", what); + udat_countSymbols(icudf, UDAT_ERAS); + subStatus = U_ILLEGAL_ARGUMENT_ERROR; /* should have an errorcode. */ + if(subStatus == expectStatus) { + log_verbose("Success: did not crash on %s, but got %s.\n", what, u_errorName(subStatus)); + } else { + log_err("FAIL: didn't crash on %s, but got success %s instead of %s. \n", what, u_errorName(subStatus), u_errorName(expectStatus)); + } + } + + udat_close(icudf); + } else { + log_err("FAIL: err %s\n", u_errorName(status)); + } +} + #endif /* #if !UCONFIG_NO_FORMATTING */