ICU-6153 Prevent crash for large ChoiceFormat values by using the correct printf specification.

X-SVN-Rev: 23276
This commit is contained in:
George Rhoten 2008-01-21 17:27:53 +00:00
parent 4999616984
commit e8e7c73d8a
6 changed files with 38 additions and 141 deletions

View File

@ -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,9 +240,9 @@ 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;
@ -254,6 +254,7 @@ ChoiceFormat::dtos(double value,
break;
}
}
}
string = UnicodeString(temp, -1, US_INV); /* invariant codepage */
return string;
}
@ -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; i<fCount; ++i) {
fClosures[i] = FALSE;
}
}
}
}
#endif
// -------------------------------------
// Sets the limit and format arrays.
void

View File

@ -1,6 +1,6 @@
/*
********************************************************************************
* Copyright (C) 1997-2005, International Business Machines
* Copyright (C) 1997-2008, International Business Machines
* Corporation and others. All Rights Reserved.
********************************************************************************
*
@ -382,40 +382,6 @@ public:
*/
virtual UnicodeString& toPattern(UnicodeString &pattern) const;
#ifdef U_USE_CHOICE_FORMAT_DEPRECATES
/**
* Set the choices to be used in formatting. The arrays are adopted and
* should not be deleted by the caller.
*
* @param limitsToAdopt Contains the top value that you want
* parsed with that format,and should be in
* ascending sorted order. When formatting X,
* the choice will be the i, where limit[i]
* &lt;= X &lt; limit[i+1].
* @param formatsToAdopt The format strings you want to use for each limit.
* @param count The size of the above arrays.
* @obsolete ICU 2.6. Use setChoices instead since this API will be removed in that release.
*/
virtual void adoptChoices(double* limitsToAdopt,
UnicodeString* formatsToAdopt,
int32_t count );
/**
* Set the choices to be used in formatting. The arrays are adopted
* and should not be deleted by the caller. See class description
* for documenatation of the limits, closures, and formats arrays.
* @param limitsToAdopt Array of limits to adopt
* @param closuresToAdopt Array of limit booleans to adopt
* @param formatsToAdopt Array of format string to adopt
* @param count The size of the above arrays
* @obsolete ICU 2.6. Use setChoices instead since this API will be removed in that release.
*/
virtual void adoptChoices(double* limitsToAdopt,
UBool* closuresToAdopt,
UnicodeString* formatsToAdopt,
int32_t count);
#endif
/**
* Set the choices to be used in formatting.
*

View File

@ -1,6 +1,6 @@
/***********************************************************************
* COPYRIGHT:
* Copyright (c) 1997-2005, International Business Machines Corporation
* Copyright (c) 1997-2008, International Business Machines Corporation
* and others. All Rights Reserved.
***********************************************************************/
@ -153,7 +153,7 @@ void MessageFormatRegressionTest::Test4058973()
UnicodeString pat;
pat = fmt->toPattern(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 += "<are negative|0.0<are no or fraction|1.0#is one|1.0<is 1+|";
pattern += "<are negative|0<are no or fraction|1#is one|1<is 1+|";
pattern += (UChar) 0x221E;
pattern += "<are many.";

View File

@ -1,7 +1,7 @@
/********************************************************************
* COPYRIGHT:
* Copyright (c) 1997-2005, International Business Machines Corporation and
* Copyright (c) 1997-2008, International Business Machines Corporation and
* others. All Rights Reserved.
********************************************************************/
@ -26,6 +26,7 @@ void TestChoiceFormat::runIndexedTest(int32_t index, UBool exec,
TESTCASE(1,TestComplexExample);
TESTCASE(2,TestClosures);
TESTCASE(3,TestPatterns);
TESTCASE(4,TestChoiceFormatToPatternOverflow);
default: name = ""; break;
}
}
@ -78,21 +79,6 @@ TestChoiceFormat::TestSimpleExample( void )
errln("ERROR: ==operator failed\n");
}
delete formequal;
#ifdef U_USE_CHOICE_FORMAT_DEPRECATES
//Testing adoptChoices()
double *limitsToAdopt = (double *)uprv_malloc(7 * sizeof(double));
UnicodeString *monthNamesToAdopt = new UnicodeString[7];
uprv_arrayCopy(monthNames, monthNamesToAdopt, 7);
uprv_memcpy(limitsToAdopt, limits, (size_t)(7 * sizeof(limits[0])));
formnew->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 */

View File

@ -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,

View File

@ -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<are {0, number} files} on disk {1}. ";
const UnicodeString pattern = "There {0,choice,0#are no files|1#is one file|1<are {0, number} files} on disk {1}. ";
logln("The input pattern : " + pattern);
MessageFormat *fmt = new MessageFormat(pattern, status);
if (U_FAILURE(status)) {