X-Git-Url: https://git.saurik.com/apple/icu.git/blobdiff_plain/b331163bffd790ced0e88b73f44f86d49ccc48a5..f3c0d7a59d99c2a94c6b8822291f0e42be3773c9:/icuSources/common/locid.cpp diff --git a/icuSources/common/locid.cpp b/icuSources/common/locid.cpp index 27e40306..36508aca 100644 --- a/icuSources/common/locid.cpp +++ b/icuSources/common/locid.cpp @@ -1,6 +1,8 @@ +// © 2016 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html /* ********************************************************************** - * Copyright (C) 1997-2015, International Business Machines + * Copyright (C) 1997-2016, International Business Machines * Corporation and others. All Rights Reserved. ********************************************************************** * @@ -31,6 +33,7 @@ #include "unicode/locid.h" +#include "unicode/strenum.h" #include "unicode/uloc.h" #include "putilimp.h" #include "mutex.h" @@ -42,6 +45,7 @@ #include "uhash.h" #include "ucln_cmn.h" #include "ustr_imp.h" +#include "charstr.h" U_CDECL_BEGIN static UBool U_CALLCONV locale_cleanup(void); @@ -57,6 +61,12 @@ static UMutex gDefaultLocaleMutex = U_MUTEX_INITIALIZER; 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 typedef enum ELocalePos { @@ -283,13 +293,12 @@ Locale::Locale( const char * newLanguage, } else { - MaybeStackArray togo; + UErrorCode status = U_ZERO_ERROR; int32_t size = 0; int32_t lsize = 0; int32_t csize = 0; int32_t vsize = 0; int32_t ksize = 0; - char *p; // Calculate the size of the resulting string. @@ -297,13 +306,23 @@ Locale::Locale( const char * newLanguage, if ( newLanguage != NULL ) { 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 if ( newCountry != NULL ) { csize = (int32_t)uprv_strlen(newCountry); + if ( csize < 0 || csize > ULOC_STRING_LIMIT ) { // int32 wrap + setToBogus(); + return; + } size += csize; } @@ -318,6 +337,10 @@ Locale::Locale( const char * newLanguage, // 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) ) { vsize--; @@ -342,70 +365,56 @@ Locale::Locale( const char * newLanguage, if ( newKeywords != NULL) { ksize = (int32_t)uprv_strlen(newKeywords); + if ( ksize < 0 || ksize > ULOC_STRING_LIMIT ) { + setToBogus(); + return; + } size += ksize + 1; } - // 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); } if ( ksize != 0) { 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); } } @@ -536,7 +545,7 @@ Locale& Locale::init(const char* localeID, UBool canonicalize) /* after uloc_getName/canonicalize() we know that only '_' are separators */ separator = field[0] = fullName; fieldIdx = 1; - while ((separator = uprv_strchr(field[fieldIdx-1], SEP_CHAR)) && fieldIdx < (int32_t)(sizeof(field)/sizeof(field[0]))-1) { + while ((separator = uprv_strchr(field[fieldIdx-1], SEP_CHAR)) && fieldIdx < UPRV_LENGTHOF(field)-1) { field[fieldIdx] = separator + 1; fieldLen[fieldIdx-1] = (int32_t)(separator - field[fieldIdx-1]); fieldIdx++; @@ -662,6 +671,7 @@ Locale::setToBogus() { *script = 0; *country = 0; fIsBogus = TRUE; + variantBegin = 0; } const Locale& U_EXPORT2