From e8e7c73d8a4368bbe1f03e369d927d6d113ca1a0 Mon Sep 17 00:00:00 2001 From: George Rhoten Date: Mon, 21 Jan 2008 17:27:53 +0000 Subject: [PATCH] ICU-6153 Prevent crash for large ChoiceFormat values by using the correct printf specification. X-SVN-Rev: 23276 --- icu4c/source/i18n/choicfmt.cpp | 73 ++++--------------------- icu4c/source/i18n/unicode/choicfmt.h | 36 +----------- icu4c/source/test/intltest/msfmrgts.cpp | 6 +- icu4c/source/test/intltest/tchcfmt.cpp | 57 ++++++------------- icu4c/source/test/intltest/tchcfmt.h | 3 +- icu4c/source/test/intltest/tmsgfmt.cpp | 4 +- 6 files changed, 38 insertions(+), 141 deletions(-) diff --git a/icu4c/source/i18n/choicfmt.cpp b/icu4c/source/i18n/choicfmt.cpp index 63b1a9d1fdf..89666e27d90 100644 --- a/icu4c/source/i18n/choicfmt.cpp +++ b/icu4c/source/i18n/choicfmt.cpp @@ -232,7 +232,7 @@ ChoiceFormat::dtos(double value, char *itrPtr = temp; char *startPtr; - sprintf(temp, "%.*f", DBL_DIG, value); + sprintf(temp, "%.*g", DBL_DIG, value); /* Find and convert the decimal point. Using setlocale on some machines will cause sprintf to use a comma for certain locales. @@ -240,18 +240,19 @@ ChoiceFormat::dtos(double value, while (*itrPtr && (*itrPtr == '-' || isdigit(*itrPtr))) { itrPtr++; } - if (*itrPtr) { + /* Have we reached something that looks like a decimal point? */ + if (*itrPtr != 0 && *itrPtr != 'e') { *itrPtr = '.'; - } - /* remove trailing zeros, except the one after '.' */ - startPtr = itrPtr + 1; - itrPtr = uprv_strchr(startPtr, 0); - while(--itrPtr > startPtr){ - if(*itrPtr == '0'){ - *itrPtr = 0; - }else{ - break; + /* remove trailing zeros, except the one after '.' */ + startPtr = itrPtr + 1; + itrPtr = uprv_strchr(startPtr, 0); + while(--itrPtr > startPtr){ + if(*itrPtr == '0'){ + *itrPtr = 0; + }else{ + break; + } } } string = UnicodeString(temp, -1, US_INV); /* invariant codepage */ @@ -490,56 +491,6 @@ ChoiceFormat::toPattern(UnicodeString& result) const return result; } -#ifdef U_USE_CHOICE_FORMAT_DEPRECATES -// ------------------------------------- -// Adopts the limit and format arrays. - -void -ChoiceFormat::adoptChoices(double *limits, - UnicodeString *formats, - int32_t cnt ) -{ - adoptChoices(limits, (UBool *)0, formats, cnt); -} - -// ------------------------------------- -// Adopts the limit and format arrays. - -void -ChoiceFormat::adoptChoices(double *limits, - UBool *closures, - UnicodeString *formats, - int32_t cnt ) -{ - if(limits == 0 || formats == 0) - return; - - if (fChoiceLImits) { - uprv_free(fChoiceLimits); - } - if (fClosures) { - uprv_free(fClosures); - } - if (fChoiceFormats) { - delete [] fChoiceFormats; - } - fChoiceLimits = limits; - fClosures = closures; - fChoiceFormats = formats; - fCount = cnt; - - if (fClosures == 0) { - fClosures = (UBool*) uprv_malloc( sizeof(UBool) * fCount); - if (fClosures != NULL) { - int32_t i; - for (i=0; itoPattern(pat); - UnicodeString exp("{0,choice,0.0#no files|1.0#one file|1.0< {0,number,integer} files}"); + UnicodeString exp("{0,choice,0#no files|1#one file|1< {0,number,integer} files}"); if (pat != exp) { errln("MessageFormat.toPattern failed"); errln("Exp: " + exp); @@ -628,7 +628,7 @@ void MessageFormatRegressionTest::Test4094906() UErrorCode status = U_ZERO_ERROR; UnicodeString pattern("-"); pattern += (UChar) 0x221E; - pattern += "adoptChoices(limitsToAdopt, monthNamesToAdopt, 7); - if(!(*formnew == *form)){ - errln("ERROR: ==Operator or adoptChoices failed\n"); - } -#endif - delete formnew; //Testing getLimits() @@ -179,7 +165,7 @@ TestChoiceFormat::TestComplexExample( void ) it_logln("MessageFormat toPattern: " + res1); fileform->toPattern( res1 ); it_logln("ChoiceFormat toPattern: " + res1); - if (res1 == "-1.0#are corrupted files|0.0#are no files|1.0#is one file|2.0#are {2} files") { + if (res1 == "-1#are corrupted files|0#are no files|1#is one file|2#are {2} files") { it_logln("toPattern tested!"); }else{ it_errln("*** ChoiceFormat to Pattern result!"); @@ -348,38 +334,19 @@ TestChoiceFormat::TestComplexExample( void ) } form_pat.toPattern( res1 ); - if (res1 == "0.0#none|1.0#one|2.0#many") { + if (res1 == "0#none|1#one|2#many") { it_logln("ChoiceFormat contructor( newPattern, status) tested"); }else{ it_errln("*** ChoiceFormat contructor( newPattern, status) or toPattern result!"); } -#ifdef U_USE_CHOICE_FORMAT_DEPRECATES - double* d_a = (double *)uprv_malloc(2 * sizeof(double)); - if (!d_a) { it_errln("*** allocation error."); return; } - d_a[0] = 1.0; d_a[1] = 2.0; - - UnicodeString* s_a = new UnicodeString[2]; - if (!s_a) { it_errln("*** allocation error."); return; } - s_a[0] = "first"; s_a[1] = "second"; - - form_pat.adoptChoices( d_a, s_a, 2 ); - form_pat.toPattern( res1 ); - it_out << "ChoiceFormat adoptChoices toPattern: " << res1 << endl; - if (res1 == "1.0#first|2.0#second") { - it_logln("ChoiceFormat adoptChoices tested"); - }else{ - it_errln("*** ChoiceFormat adoptChoices result!"); - } -#endif - double d_a2[] = { 3.0, 4.0 }; UnicodeString s_a2[] = { "third", "forth" }; form_pat.setChoices( d_a2, s_a2, 2 ); form_pat.toPattern( res1 ); it_logln(UnicodeString("ChoiceFormat adoptChoices toPattern: ") + res1); - if (res1 == "3.0#third|4.0#forth") { + if (res1 == "3#third|4#forth") { it_logln("ChoiceFormat adoptChoices tested"); }else{ it_errln("*** ChoiceFormat adoptChoices result!"); @@ -497,7 +464,7 @@ void TestChoiceFormat::TestClosures(void) { // 'fmt2' is created using a pattern; it should be equivalent UErrorCode status = U_ZERO_ERROR; - const char* PAT = "0.0#,1)|1.0#[1,2]|2.0<(2,3]|3.0<(3,4)|4.0#[4,5)|5.0#[5,"; + const char* PAT = "0#,1)|1#[1,2]|2<(2,3]|3<(3,4)|4#[4,5)|5#[5,"; ChoiceFormat fmt2(PAT, status); if (U_FAILURE(status)) { errln("FAIL: ChoiceFormat constructor failed"); @@ -649,4 +616,16 @@ void TestChoiceFormat::TestPatterns(void) { 0, 0, 0, 0, 0, 0); } +void TestChoiceFormat::TestChoiceFormatToPatternOverflow() +{ + static const double limits[] = {0.1e-78, 1e13, 0.1e78}; + UnicodeString monthNames[] = { "one", "two", "three" }; + ChoiceFormat fmt(limits, monthNames, sizeof(limits)/sizeof(limits[0])); + UnicodeString patStr, expectedPattern("1e-079#one|10000000000000#two|1e+077#three"); + fmt.toPattern(patStr); + if (patStr != expectedPattern) { + errln("ChoiceFormat returned \"" + patStr + "\" instead of \"" + expectedPattern + "\""); + } +} + #endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/icu4c/source/test/intltest/tchcfmt.h b/icu4c/source/test/intltest/tchcfmt.h index ade2027a52f..caa3e2e638d 100644 --- a/icu4c/source/test/intltest/tchcfmt.h +++ b/icu4c/source/test/intltest/tchcfmt.h @@ -1,7 +1,7 @@ /******************************************************************** * COPYRIGHT: - * Copyright (c) 1997-2003, International Business Machines Corporation and + * Copyright (c) 1997-2008, International Business Machines Corporation and * others. All Rights Reserved. ********************************************************************/ @@ -40,6 +40,7 @@ class TestChoiceFormat: public IntlTest { * Test applyPattern */ void TestPatterns(void); + void TestChoiceFormatToPatternOverflow(void); void _testPattern(const char* pattern, UBool isValid, diff --git a/icu4c/source/test/intltest/tmsgfmt.cpp b/icu4c/source/test/intltest/tmsgfmt.cpp index 8cadf8665c1..4aeccb04577 100644 --- a/icu4c/source/test/intltest/tmsgfmt.cpp +++ b/icu4c/source/test/intltest/tmsgfmt.cpp @@ -1,5 +1,5 @@ /******************************************************************** - * Copyright (c) 1997-2007, International Business Machines + * Copyright (c) 1997-2008, International Business Machines * Corporation and others. All Rights Reserved. ******************************************************************** * File TMSGFMT.CPP @@ -162,7 +162,7 @@ void TestMessageFormat::testBug2() UErrorCode status = U_ZERO_ERROR; UnicodeString result; // {sfb} use double format in pattern, so result will match (not strictly necessary) - const UnicodeString pattern = "There {0,choice,0.0#are no files|1.0#is one file|1.0