Kaynağa Gözat

Intl: Fail silently if windows.globalization.dll is missing

Chakracore doesn't work on Windows 7 machines that doesn't have IE11.
We try to load `jsintl.dll` while trying to initialize `JavascriptLibrary` but throw
Error if we fail to load these binaries. This makes Chakracore unusable for
Win7 minus IE11 machines.

The fix is to ignore the error silently and keep executing. The downside to this is
`Intl` object will not be available on global object and hence below properties won't
be available because these properties are populated based on globalization dlls.

```js
Intl.Collator
Intl.DateTimeFormat
Intl.NumberFormat
```

There are also specific locale specific APIs related to DateTime that won't work
without globalization support.

The upside is Chakracore will work on these machines for non-locale javascript code.
Kunal Pathak 10 yıl önce
ebeveyn
işleme
6d93f61590

+ 23 - 15
lib/Parser/CharClassifier.cpp

@@ -619,28 +619,36 @@ void Js::CharClassifier::initClassifier(ScriptContext * scriptContext, CharClass
     if (es6ModeNeeded)
     {
         HRESULT hr = globalizationAdapter->EnsureDataTextObjectsInitialized(globLibrary);
+        // Failed to load windows.globalization.dll or jsintl.dll. No unicodeStatics support
+        // in that case.
         if (FAILED(hr))
         {
-            AssertMsg(false, "Failed to initialize COM interfaces, verify correct version of globalization dll is used.");
-            JavascriptError::MapAndThrowError(scriptContext, hr);
-        }
-
-        this->winGlobCharApi = globalizationAdapter->GetUnicodeStatics();
-        if (this->winGlobCharApi == nullptr)
-        {
-            // No fallback mode, then assert
-            if (es6FallbackMode == CharClassifierModes::ES6)
-            {
-                AssertMsg(false, "Windows::Data::Text::IUnicodeCharactersStatics not initialized");
-                //Fallback to ES5 just in case for fre builds.
-                es6FallbackMode = CharClassifierModes::ES5;
-            }
             if (isES6UnicodeVerboseEnabled)
             {
                 Output::Print(L"Windows::Data::Text::IUnicodeCharactersStatics not initialized\r\n");
             }
-            //Default to non-es6
             es6Supported = false;
+            es6FallbackMode = CharClassifierModes::ES5;
+        }
+        else
+        {
+            this->winGlobCharApi = globalizationAdapter->GetUnicodeStatics();
+            if (this->winGlobCharApi == nullptr)
+            {
+                // No fallback mode, then assert
+                if (es6FallbackMode == CharClassifierModes::ES6)
+                {
+                    AssertMsg(false, "Windows::Data::Text::IUnicodeCharactersStatics not initialized");
+                    //Fallback to ES5 just in case for fre builds.
+                    es6FallbackMode = CharClassifierModes::ES5;
+                }
+                if (isES6UnicodeVerboseEnabled)
+                {
+                    Output::Print(L"Windows::Data::Text::IUnicodeCharactersStatics not initialized\r\n");
+                }
+                //Default to non-es6
+                es6Supported = false;
+            }
         }
     }
 #else

+ 10 - 0
lib/Runtime/Base/DelayLoadLibrary.cpp

@@ -176,6 +176,11 @@ namespace Js
         return E_NOTIMPL;
     }
 
+    bool DelayLoadWindowsGlobalization::HasGlobalizationDllLoaded()
+    {
+        return this->hasGlobalizationDllLoaded;
+    }
+
     HRESULT DelayLoadWindowsGlobalization::DllGetActivationFactory(
         __in HSTRING activatibleClassId,
         __out IActivationFactory** factory)
@@ -268,6 +273,11 @@ namespace Js
                 m_hModule = LoadLibraryEx(GetWin7LibraryName(), nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32);
             }
 
+            // Set the flag depending on Windows.globalization.dll or jsintl.dll was loaded successfully or not
+            if (m_hModule != nullptr)
+            {
+                hasGlobalizationDllLoaded = true;
+            }
             this->winRTStringLibrary = winRTStringLibrary;
             this->winRTStringsPresent = GetFunction("WindowsDuplicateString") != nullptr;
         }

+ 5 - 2
lib/Runtime/Base/DelayLoadLibrary.h

@@ -166,13 +166,15 @@ namespace Js
         PFNCWDllGetActivationFactory m_pfnFNCWDllGetActivationFactory;
 
         Js::DelayLoadWinRtString *winRTStringLibrary;
-        BOOL winRTStringsPresent;
+        bool winRTStringsPresent;
+        bool hasGlobalizationDllLoaded;
 
     public:
         DelayLoadWindowsGlobalization() : DelayLoadWinRtString(),
             m_pfnFNCWDllGetActivationFactory(nullptr),
             winRTStringLibrary(nullptr),
-            winRTStringsPresent(false) { }
+            winRTStringsPresent(false),
+            hasGlobalizationDllLoaded(false) { }
 
         virtual ~DelayLoadWindowsGlobalization() { }
 
@@ -187,6 +189,7 @@ namespace Js
         void Ensure(Js::DelayLoadWinRtString *winRTStringLibrary);
 
         HRESULT DllGetActivationFactory(__in HSTRING activatibleClassId, __out IActivationFactory** factory);
+        bool HasGlobalizationDllLoaded();
 
         HRESULT WindowsCreateString(_In_reads_opt_(length) const WCHAR * sourceString, UINT32 length, _Outptr_result_maybenull_ _Result_nullonfailure_ HSTRING * string) override;
         HRESULT WindowsCreateStringReference(_In_reads_opt_(length+1) const WCHAR * sourceString, UINT32 length, _Out_ HSTRING_HEADER * header, _Outptr_result_maybenull_ _Result_nullonfailure_ HSTRING * string) override;

+ 11 - 0
lib/Runtime/Base/ScriptContext.cpp

@@ -5239,6 +5239,17 @@ void ScriptContext::RegisterPrototypeChainEnsuredToHaveOnlyWritableDataPropertie
         return false;
     }
 
+    bool ScriptContext::IsIntlEnabled()
+    {
+        if (GetConfig()->IsIntlEnabled())
+        {
+            // This will try to load globalization dlls if not already loaded.
+            Js::DelayLoadWindowsGlobalization* globLibrary = GetThreadContext()->GetWindowsGlobalizationLibrary();
+            return globLibrary->HasGlobalizationDllLoaded();
+        }
+        return false;
+    }
+
 
 #ifdef INLINE_CACHE_STATS
     void ScriptContext::LogCacheUsage(Js::PolymorphicInlineCache *cache, bool isGetter, Js::PropertyId propertyId, bool hit, bool collision)

+ 1 - 0
lib/Runtime/Base/ScriptContext.h

@@ -913,6 +913,7 @@ private:
         void RestoreRegexStacks(UnifiedRegex::RegexStacks *const contStack);
 
         void InitializeGlobalObject();
+        bool IsIntlEnabled();
         JavascriptLibrary* GetLibrary() const { return javascriptLibrary; }
         const JavascriptLibraryBase* GetLibraryBase() const { return javascriptLibrary->GetLibraryBase(); }
 #if DBG

+ 11 - 8
lib/Runtime/Library/IntlEngineInterfaceExtensionObject.cpp

@@ -30,8 +30,11 @@ using namespace Windows::Globalization;
 
 #pragma warning(pop)
 
-#define IfCOMFailAssertMsgAndThrowHr(op) \
-   IfFailAssertMsgAndThrowHr(op, "Failed to initialize COM interfaces, verify correct version of globalization dll is used.")
+#define IfCOMFailIgnoreSilentlyAndReturn(op) \
+    if(FAILED(hr=(op))) \
+    { \
+        return; \
+    } \
 
 #define IfFailAssertMsgAndThrowHr(op, msg) \
     if (FAILED(hr=(op))) \
@@ -233,7 +236,7 @@ namespace Js
         }
         JavascriptLibrary* library = scriptContext->GetLibrary();
         DynamicObject* commonObject = library->GetEngineInterfaceObject()->GetCommonNativeInterfaces();
-        if (scriptContext->GetConfig()->IsIntlEnabled())
+        if (scriptContext->IsIntlEnabled())
         {
             Assert(library->GetEngineInterfaceObject() != nullptr);
             this->intlNativeInterfaces = DynamicObject::New(library->GetRecycler(),
@@ -383,7 +386,7 @@ namespace Js
             JavascriptString* initType = nullptr;
 
             //Ensure we have initialized all appropriate COM objects for the adapter (we will be using them now)
-            IfCOMFailAssertMsgAndThrowHr(GetWindowsGlobalizationAdapter(scriptContext)->EnsureCommonObjectsInitialized(library));
+            IfCOMFailIgnoreSilentlyAndReturn(globAdapter->EnsureCommonObjectsInitialized(library));
             switch (intlInitializationType)
             {
                 default:
@@ -391,8 +394,8 @@ namespace Js
                     // fall thru
                 case IntlInitializationType::Intl:
 
-                    IfCOMFailAssertMsgAndThrowHr(globAdapter->EnsureNumberFormatObjectsInitialized(library));
-                    IfCOMFailAssertMsgAndThrowHr(globAdapter->EnsureDateTimeFormatObjectsInitialized(library));
+                    IfCOMFailIgnoreSilentlyAndReturn(globAdapter->EnsureNumberFormatObjectsInitialized(library));
+                    IfCOMFailIgnoreSilentlyAndReturn(globAdapter->EnsureDateTimeFormatObjectsInitialized(library));
                     initType = scriptContext->GetLibrary()->CreateStringFromCppLiteral(L"Intl");
                     break;
                 case IntlInitializationType::StringPrototype:
@@ -400,11 +403,11 @@ namespace Js
                     initType = scriptContext->GetLibrary()->CreateStringFromCppLiteral(L"String");
                     break;
                 case IntlInitializationType::DatePrototype:
-                    IfCOMFailAssertMsgAndThrowHr(globAdapter->EnsureDateTimeFormatObjectsInitialized(library));
+                    IfCOMFailIgnoreSilentlyAndReturn(globAdapter->EnsureDateTimeFormatObjectsInitialized(library));
                     initType = scriptContext->GetLibrary()->CreateStringFromCppLiteral(L"Date");
                     break;
                 case IntlInitializationType::NumberPrototype:
-                    IfCOMFailAssertMsgAndThrowHr(globAdapter->EnsureNumberFormatObjectsInitialized(library));
+                    IfCOMFailIgnoreSilentlyAndReturn(globAdapter->EnsureNumberFormatObjectsInitialized(library));
                     initType = scriptContext->GetLibrary()->CreateStringFromCppLiteral(L"Number");
                     break;
             }

+ 3 - 3
lib/Runtime/Library/JavascriptDate.cpp

@@ -1306,7 +1306,7 @@ namespace Js
         JavascriptDate* date = JavascriptDate::FromVar(args[0]);
 
 #ifdef ENABLE_INTL_OBJECT
-        if (CONFIG_FLAG(IntlBuiltIns) && scriptContext->GetConfig()->IsIntlEnabled()){
+        if (CONFIG_FLAG(IntlBuiltIns) && scriptContext->IsIntlEnabled()){
 
             EngineInterfaceObject* nativeEngineInterfaceObj = scriptContext->GetLibrary()->GetEngineInterfaceObject();
             if (nativeEngineInterfaceObj)
@@ -1357,7 +1357,7 @@ namespace Js
         JavascriptDate* date = JavascriptDate::FromVar(args[0]);
 
 #ifdef ENABLE_INTL_OBJECT
-        if (CONFIG_FLAG(IntlBuiltIns) && scriptContext->GetConfig()->IsIntlEnabled()){
+        if (CONFIG_FLAG(IntlBuiltIns) && scriptContext->IsIntlEnabled()){
 
             EngineInterfaceObject* nativeEngineInterfaceObj = scriptContext->GetLibrary()->GetEngineInterfaceObject();
             if (nativeEngineInterfaceObj)
@@ -1416,7 +1416,7 @@ namespace Js
         JavascriptDate* date = JavascriptDate::FromVar(args[0]);
 
 #ifdef ENABLE_INTL_OBJECT
-        if (CONFIG_FLAG(IntlBuiltIns) && scriptContext->GetConfig()->IsIntlEnabled()){
+        if (CONFIG_FLAG(IntlBuiltIns) && scriptContext->IsIntlEnabled()){
 
             EngineInterfaceObject* nativeEngineInterfaceObj = scriptContext->GetLibrary()->GetEngineInterfaceObject();
             if (nativeEngineInterfaceObj)

+ 1 - 1
lib/Runtime/Library/JavascriptLibrary.cpp

@@ -1484,7 +1484,7 @@ namespace Js
         AddMember(globalObject, PropertyIds::JSON, JSONObject);
 
 #ifdef ENABLE_INTL_OBJECT
-        if (scriptContext->GetConfig()->IsIntlEnabled())
+        if (scriptContext->IsIntlEnabled())
         {
             IntlObject = DynamicObject::New(recycler,
                 DynamicType::New(scriptContext, TypeIds_Object, objectPrototype, nullptr,

+ 1 - 1
lib/Runtime/Library/JavascriptNumber.cpp

@@ -652,7 +652,7 @@ namespace Js
         }
 
 #ifdef ENABLE_INTL_OBJECT
-        if(CONFIG_FLAG(IntlBuiltIns) && scriptContext->GetConfig()->IsIntlEnabled()){
+        if(CONFIG_FLAG(IntlBuiltIns) && scriptContext->IsIntlEnabled()){
 
             EngineInterfaceObject* nativeEngineInterfaceObj = scriptContext->GetLibrary()->GetEngineInterfaceObject();
             if (nativeEngineInterfaceObj)

+ 1 - 1
lib/Runtime/Library/JavascriptString.cpp

@@ -1302,7 +1302,7 @@ case_2:
         GetThisAndSearchStringArguments(args, scriptContext, L"String.prototype.localeCompare", &pThis, &pThat, true);
 
 #ifdef ENABLE_INTL_OBJECT
-        if (CONFIG_FLAG(IntlBuiltIns) && scriptContext->GetConfig()->IsIntlEnabled())
+        if (CONFIG_FLAG(IntlBuiltIns) && scriptContext->IsIntlEnabled())
         {
             EngineInterfaceObject* nativeEngineInterfaceObj = scriptContext->GetLibrary()->GetEngineInterfaceObject();
             if (nativeEngineInterfaceObj)

+ 2 - 2
test/es6/rlexe.xml

@@ -481,7 +481,7 @@
       <files>unicode_6_identifiers.js</files>
       <baseline>unicode_6_identifiers.baseline</baseline>
       <compile-flags> -ES6Unicode</compile-flags>
-      <tags>exclude_ship</tags>
+      <tags>exclude_win7,exclude_ship</tags>
     </default>
   </test>
   <test>
@@ -984,7 +984,7 @@
   <test>
     <default>
       <files>bug_OS_2553885.js</files>
-      <tags>BugFix</tags>
+      <tags>exclude_win7,BugFix</tags>
     </default>
   </test>
   <test>