| Index: source/common/locid.cpp
|
| diff --git a/source/common/locid.cpp b/source/common/locid.cpp
|
| index 27e403065f2e933c99c215e6d2de93f856c5981f..d2781db95bdd8cf8b4e0c31f9659406add9e299e 100644
|
| --- a/source/common/locid.cpp
|
| +++ b/source/common/locid.cpp
|
| @@ -1,6 +1,8 @@
|
| +// Copyright (C) 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.
|
| **********************************************************************
|
| *
|
| @@ -42,6 +44,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 +60,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 +292,12 @@ Locale::Locale( const char * newLanguage,
|
| }
|
| else
|
| {
|
| - MaybeStackArray<char, ULOC_FULLNAME_CAPACITY> 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 +305,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 +336,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 +364,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 +544,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 +670,7 @@ Locale::setToBogus() {
|
| *script = 0;
|
| *country = 0;
|
| fIsBogus = TRUE;
|
| + variantBegin = 0;
|
| }
|
|
|
| const Locale& U_EXPORT2
|
|
|