Index: icu/trunk/source/common/locid.cpp
===================================================================
--- icu/source/common/locid.cpp	(revision 39282)
+++ icu/source/common/locid.cpp	(revision 39384)
@@ -45,4 +45,5 @@
 #include "ucln_cmn.h"
 #include "ustr_imp.h"
+#include "charstr.h"
 
 U_CDECL_BEGIN
@@ -59,4 +60,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
@@ -286,5 +293,5 @@
     else
     {
-        MaybeStackArray<char, ULOC_FULLNAME_CAPACITY> togo;
+        UErrorCode status = U_ZERO_ERROR;
         int32_t size = 0;
         int32_t lsize = 0;
@@ -292,5 +299,4 @@
         int32_t vsize = 0;
         int32_t ksize = 0;
-        char    *p;
 
         // Calculate the size of the resulting string.
@@ -300,6 +306,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
@@ -307,4 +319,8 @@
         {
             csize = (int32_t)uprv_strlen(newCountry);
+            if ( csize < 0 || csize > ULOC_STRING_LIMIT ) { // int32 wrap
+                setToBogus();
+                return;
+            }
             size += csize;
         }
@@ -321,4 +337,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) )
             {
@@ -345,48 +365,30 @@
         {
             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);
         }
 
@@ -394,19 +396,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);
     }
 }
