]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/common/locid.cpp
ICU-59173.0.1.tar.gz
[apple/icu.git] / icuSources / common / locid.cpp
index d6ca74dfafeb646c1a0a031cbb40adf52f694270..36508acaf5ca70c2fadba2fe1b5f6f0078dc5f97 100644 (file)
@@ -1,3 +1,5 @@
+// © 2016 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
 /*
  **********************************************************************
  *   Copyright (C) 1997-2016, International Business Machines
@@ -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<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 +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);
     }
 }
 
@@ -662,6 +671,7 @@ Locale::setToBogus() {
     *script = 0;
     *country = 0;
     fIsBogus = TRUE;
+    variantBegin = 0;
 }
 
 const Locale& U_EXPORT2