Index: source/common/locid.cpp =================================================================== --- a/source/common/locid.cpp (revision 39353) +++ b/source/common/locid.cpp (revision 39356) @@ -43,4 +43,5 @@ #include "ucln_cmn.h" #include "ustr_imp.h" +#include "charstr.h" U_CDECL_BEGIN @@ -57,4 +58,10 @@ static UHashtable *gDefaultLocalesHashT = NULL; static Locale *gDefaultLocale = NULL; + +/** + * \def ULOC_STRING_LIMIT + * strings beyond this value crash in CharString + */ +#define ULOC_STRING_LIMIT 357913941 U_NAMESPACE_END @@ -284,5 +291,5 @@ else { - MaybeStackArray togo; + UErrorCode status = U_ZERO_ERROR; int32_t size = 0; int32_t lsize = 0; @@ -290,5 +297,4 @@ int32_t vsize = 0; int32_t ksize = 0; - char *p; // Calculate the size of the resulting string. @@ -298,6 +304,12 @@ { lsize = (int32_t)uprv_strlen(newLanguage); + if ( lsize < 0 || lsize > ULOC_STRING_LIMIT ) { // int32 wrap + setToBogus(); + return; + } size = lsize; } + + CharString togo(newLanguage, lsize, status); // start with newLanguage // _Country @@ -305,4 +317,8 @@ { csize = (int32_t)uprv_strlen(newCountry); + if ( csize < 0 || csize > ULOC_STRING_LIMIT ) { // int32 wrap + setToBogus(); + return; + } size += csize; } @@ -319,4 +335,8 @@ // remove trailing _'s vsize = (int32_t)uprv_strlen(newVariant); + if ( vsize < 0 || vsize > ULOC_STRING_LIMIT ) { // int32 wrap + setToBogus(); + return; + } while( (vsize>1) && (newVariant[vsize-1] == SEP_CHAR) ) { @@ -343,48 +363,34 @@ { ksize = (int32_t)uprv_strlen(newKeywords); + if ( ksize < 0 || ksize > ULOC_STRING_LIMIT ) { + setToBogus(); + return; + } size += ksize + 1; } - + if (size < 0) { + setToBogus(); + return; + } // NOW we have the full locale string.. - - /*if the whole string is longer than our internal limit, we need - to go to the heap for temporary buffers*/ - if (size >= togo.getCapacity()) - { - // If togo_heap could not be created, initialize with default settings. - if (togo.resize(size+1) == NULL) { - init(NULL, FALSE); - } - } - - togo[0] = 0; - // Now, copy it back. - p = togo.getAlias(); - if ( lsize != 0 ) - { - uprv_strcpy(p, newLanguage); - p += lsize; - } + + // newLanguage is already copied if ( ( vsize != 0 ) || (csize != 0) ) // at least: __v { // ^ - *p++ = SEP_CHAR; + togo.append(SEP_CHAR, status); } if ( csize != 0 ) { - uprv_strcpy(p, newCountry); - p += csize; + togo.append(newCountry, status); } if ( vsize != 0) { - *p++ = SEP_CHAR; // at least: __v - - uprv_strncpy(p, newVariant, vsize); // Must use strncpy because - p += vsize; // of trimming (above). - *p = 0; // terminate + togo.append(SEP_CHAR, status) + .append(newVariant, vsize, status); } @@ -392,19 +398,23 @@ { if (uprv_strchr(newKeywords, '=')) { - *p++ = '@'; /* keyword parsing */ + togo.append('@', status); /* keyword parsing */ } else { - *p++ = '_'; /* Variant parsing with a script */ + togo.append('_', status); /* Variant parsing with a script */ if ( vsize == 0) { - *p++ = '_'; /* No country found */ + togo.append('_', status); /* No country found */ } } - uprv_strcpy(p, newKeywords); - p += ksize; - } - + togo.append(newKeywords, status); + } + + if (U_FAILURE(status)) { + // Something went wrong with appending, etc. + setToBogus(); + return; + } // Parse it, because for example 'language' might really be a complete // string. - init(togo.getAlias(), FALSE); + init(togo.data(), FALSE); } } Index: source/test/intltest/numfmtst.cpp =================================================================== --- a/source/test/intltest/numfmtst.cpp (revision 39353) +++ b/source/test/intltest/numfmtst.cpp (revision 39356) @@ -2421,9 +2421,10 @@ const char *localeName = badLocales[i]; Locale locBad(localeName); + TEST_ASSERT_TRUE(!locBad.isBogus()); UErrorCode status = U_ZERO_ERROR; UnicodeString intlCurrencySymbol((UChar)0xa4); intlCurrencySymbol.append((UChar)0xa4); - + logln("Current locale is %s", Locale::getDefault().getName()); Locale::setDefault(locBad, status);