Просмотр исходного кода

Add handling of more OOM scenarios in ICU

Jack Horton (CHAKRA) 7 лет назад
Родитель
Сommit
d7d4cabacc
1 измененных файлов с 32 добавлено и 4 удалено
  1. 32 4
      lib/Runtime/Library/IntlEngineInterfaceExtensionObject.cpp

+ 32 - 4
lib/Runtime/Library/IntlEngineInterfaceExtensionObject.cpp

@@ -32,7 +32,11 @@ using namespace PlatformAgnostic::ICUHelpers;
 #define ICU_ASSERT(e, expr)                                                   \
     do                                                                        \
     {                                                                         \
-        if (ICU_FAILURE(e))                                                   \
+        if (e == U_MEMORY_ALLOCATION_ERROR)                                   \
+        {                                                                     \
+            Js::Throw::OutOfMemory();                                         \
+        }                                                                     \
+        else if (ICU_FAILURE(e))                                              \
         {                                                                     \
             AssertOrFailFastMsg(false, ICU_ERRORMESSAGE(e));                  \
         }                                                                     \
@@ -400,6 +404,17 @@ namespace Js
         return ret;
     }
 
+    template <typename T>
+    static _Ret_notnull_ T AssertNotNullOrOOM(_In_ T value)
+    {
+        if (value == nullptr)
+        {
+            Throw::OutOfMemory();
+        }
+
+        return value;
+    }
+
     template <size_t N>
     static void LangtagToLocaleID(_In_count_(langtagLength) const char16 *langtag, _In_ charcount_t langtagLength, _Out_ char(&localeID)[N])
     {
@@ -1067,13 +1082,15 @@ namespace Js
             int i = 0;
             for (collation = uenum_next(collations, &collationLen, &status); collation != nullptr; collation = uenum_next(collations, &collationLen, &status))
             {
+                ICU_ASSERT(status, collation != nullptr && collationLen > 0);
                 if (strcmp(collation, "standard") == 0 || strcmp(collation, "search") == 0)
                 {
                     // continue does not create holes in ret because i is set outside the loop
                     continue;
                 }
 
-                const char *unicodeCollation = uloc_toUnicodeLocaleType("collation", collation);
+                // OS#17172584: OOM during uloc_toUnicodeLocaleType can make this return nullptr even for known collations
+                const char *unicodeCollation = AssertNotNullOrOOM(uloc_toUnicodeLocaleType("collation", collation));
                 const size_t unicodeCollationLen = strlen(unicodeCollation);
 
                 // we only need strlen(unicodeCollation) + 1 char16s because unicodeCollation will always be ASCII (funnily enough)
@@ -1161,7 +1178,10 @@ namespace Js
             int i = 0;
             for (calendar = uenum_next(calendars, &calendarLen, &status); calendar != nullptr; calendar = uenum_next(calendars, &calendarLen, &status))
             {
-                const char *unicodeCalendar = uloc_toUnicodeLocaleType("calendar", calendar);
+                ICU_ASSERT(status, calendar != nullptr && calendarLen > 0);
+
+                // OS#17172584: OOM during uloc_toUnicodeLocaleType can make this return nullptr even for known calendars
+                const char *unicodeCalendar = AssertNotNullOrOOM(uloc_toUnicodeLocaleType("calendar", calendar));
                 const size_t unicodeCalendarLen = strlen(unicodeCalendar);
 
                 // we only need strlen(unicodeCalendar) + 1 char16s because unicodeCalendar will always be ASCII (funnily enough)
@@ -2590,7 +2610,15 @@ namespace Js
         {
             int curLen = -1;
             const UChar *cur = uenum_unext(available, &curLen, &status);
-            ICU_ASSERT(status, curLen > 0);
+            ICU_ASSERT(status, true);
+            if (curLen == 0)
+            {
+                // OS#17175014: in rare cases, ICU will return U_ZERO_ERROR and a valid `cur` string but a length of 0
+                // This only happens in an OOM during uenum_(u)next
+                Throw::OutOfMemory();
+            }
+
+            AssertOrFailFast(curLen > 0);
             if (_wcsicmp(reinterpret_cast<const char16 *>(cur), tz->GetSz()) == 0)
             {
                 ucal_getCanonicalTimeZoneID(cur, curLen, match, _countof(match), nullptr, &status);