Explorar el Código

1. Add JsGetExceptionWithMetaData to ch
2. Add handler in WScript::PrintException for Error.toString failure
3. Add test case

rhuanjl hace 5 años
padre
commit
4bea2b243f

+ 2 - 0
bin/ch/ChakraRtInterface.cpp

@@ -1,5 +1,6 @@
 //-------------------------------------------------------------------------------------------------------
 // Copyright (C) Microsoft. All rights reserved.
+// Copyright (c) 2021 ChakraCore Project Contributors. All rights reserved.
 // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
 //-------------------------------------------------------------------------------------------------------
 #include "stdafx.h"
@@ -122,6 +123,7 @@ bool ChakraRTInterface::LoadChakraDll(ArgInfo* argInfo, HINSTANCE *outLibrary)
     m_jsApiHooks.pfJsrtGetArrayBufferStorage = (JsAPIHooks::JsrtGetArrayBufferStoragePtr)GetChakraCoreSymbol(library, "JsGetArrayBufferStorage");
     m_jsApiHooks.pfJsrtHasException = (JsAPIHooks::JsrtHasExceptionPtr)GetChakraCoreSymbol(library, "JsHasException");
     m_jsApiHooks.pfJsrtSetException = (JsAPIHooks::JsrtSetExceptionPtr)GetChakraCoreSymbol(library, "JsSetException");
+    m_jsApiHooks.pfJsrtGetAndClearExceptionWithMetadata = (JsAPIHooks::JsrtGetAndClearExceptiopnWithMetadataPtr)GetChakraCoreSymbol(library, "JsGetAndClearExceptionWithMetadata");
     m_jsApiHooks.pfJsrtGetAndClearException = (JsAPIHooks::JsrtGetAndClearExceptiopnPtr)GetChakraCoreSymbol(library, "JsGetAndClearException");
     m_jsApiHooks.pfJsrtCreateError = (JsAPIHooks::JsrtCreateErrorPtr)GetChakraCoreSymbol(library, "JsCreateError");
     m_jsApiHooks.pfJsrtGetRuntime = (JsAPIHooks::JsrtGetRuntimePtr)GetChakraCoreSymbol(library, "JsGetRuntime");

+ 4 - 0
bin/ch/ChakraRtInterface.h

@@ -1,5 +1,6 @@
 //-------------------------------------------------------------------------------------------------------
 // Copyright (C) Microsoft. All rights reserved.
+// Copyright (c) 2021 ChakraCore Project Contributors. All rights reserved.
 // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
 //-------------------------------------------------------------------------------------------------------
 #pragma once
@@ -58,6 +59,7 @@ struct JsAPIHooks
     typedef JsErrorCode (WINAPI *JsrtCreateErrorPtr)(JsValueRef message, JsValueRef *error);
     typedef JsErrorCode (WINAPI *JsrtHasExceptionPtr)(bool *hasException);
     typedef JsErrorCode (WINAPI *JsrtSetExceptionPtr)(JsValueRef exception);
+    typedef JsErrorCode (WINAPI *JsrtGetAndClearExceptiopnWithMetadataPtr)(JsValueRef* metadata);
     typedef JsErrorCode (WINAPI *JsrtGetAndClearExceptiopnPtr)(JsValueRef* exception);
     typedef JsErrorCode (WINAPI *JsrtGetRuntimePtr)(JsContextRef context, JsRuntimeHandle *runtime);
     typedef JsErrorCode (WINAPI *JsrtReleasePtr)(JsRef ref, unsigned int* count);
@@ -197,6 +199,7 @@ struct JsAPIHooks
     JsrtCreateErrorPtr pfJsrtCreateError;
     JsrtHasExceptionPtr pfJsrtHasException;
     JsrtSetExceptionPtr pfJsrtSetException;
+    JsrtGetAndClearExceptiopnWithMetadataPtr pfJsrtGetAndClearExceptionWithMetadata;
     JsrtGetAndClearExceptiopnPtr pfJsrtGetAndClearException;
     JsrtGetRuntimePtr pfJsrtGetRuntime;
     JsrtReleasePtr pfJsrtRelease;
@@ -428,6 +431,7 @@ public:
     static JsErrorCode WINAPI JsHasException(bool *hasException) { return HOOK_JS_API(HasException(hasException)); }
     static JsErrorCode WINAPI JsSetException(JsValueRef exception) { return HOOK_JS_API(SetException(exception)); }
     static JsErrorCode WINAPI JsGetAndClearException(JsValueRef *exception) { return HOOK_JS_API(GetAndClearException(exception)); }
+    static JsErrorCode WINAPI JsGetAndClearExceptionWithMetadata(JsValueRef * metadata) { return HOOK_JS_API(GetAndClearExceptionWithMetadata(metadata)); }
     static JsErrorCode WINAPI JsGetRuntime(JsContextRef context, JsRuntimeHandle *runtime) { return HOOK_JS_API(GetRuntime(context, runtime)); }
     static JsErrorCode WINAPI JsRelease(JsRef ref, unsigned int* count) { return HOOK_JS_API(Release(ref, count)); }
     static JsErrorCode WINAPI JsAddRef(JsRef ref, unsigned int* count) { return HOOK_JS_API(AddRef(ref, count)); }

+ 63 - 2
bin/ch/WScriptJsrt.cpp

@@ -1,5 +1,6 @@
 //-------------------------------------------------------------------------------------------------------
 // Copyright (C) Microsoft Corporation and contributors. All rights reserved.
+// Copyright (c) 2021 ChakraCore Project Contributors. All rights reserved.
 // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
 //-------------------------------------------------------------------------------------------------------
 #include "stdafx.h"
@@ -1766,10 +1767,21 @@ Error:
 bool WScriptJsrt::PrintException(LPCSTR fileName, JsErrorCode jsErrorCode, JsValueRef exception)
 {
     LPCWSTR errorTypeString = ConvertErrorCodeToMessage(jsErrorCode);
+    JsValueRef metaData = JS_INVALID_REFERENCE;
 
     if (exception == nullptr)
     {
-        ChakraRTInterface::JsGetAndClearException(&exception);
+        if (ChakraRTInterface::JsGetAndClearExceptionWithMetadata(&metaData) == JsNoError)
+        {
+            JsPropertyIdRef exceptionId = JS_INVALID_REFERENCE;
+            IfJsrtErrorFail(CreatePropertyIdFromString("exception", &exceptionId), false);
+            IfJsrtErrorFail(ChakraRTInterface::JsGetProperty(metaData, exceptionId, &exception), false);
+        }
+        else
+        {
+            IfJsrtErrorFail(ChakraRTInterface::JsGetAndClearException(&exception), false);
+        }
+
     }
 
     if (HostConfigFlags::flags.MuteHostErrorMsgIsEnabled)
@@ -1783,7 +1795,56 @@ bool WScriptJsrt::PrintException(LPCSTR fileName, JsErrorCode jsErrorCode, JsVal
         {
             AutoString errorMessage;
 
-            IfJsrtErrorFail(errorMessage.Initialize(exception), false);
+            if (errorMessage.Initialize(exception) != JsNoError)
+            {
+                fwprintf(stderr, _u("ERROR attempting to coerce error to string, using alternate handler\n"));
+                bool hasException = false;
+                ChakraRTInterface::JsHasException(&hasException);
+                if (hasException)
+                {
+                    JsValueRef throwAway = JS_INVALID_REFERENCE;
+                    ChakraRTInterface::JsGetAndClearException(&throwAway);
+                }
+                JsPropertyIdRef messagePropertyId = JS_INVALID_REFERENCE;
+                IfJsrtErrorFail(CreatePropertyIdFromString("message", &messagePropertyId), false);
+                JsValueRef message = JS_INVALID_REFERENCE;
+                IfJsrtErrorFail(ChakraRTInterface::JsGetProperty(exception, messagePropertyId, &message), false);
+                IfJsrtErrorFail(errorMessage.Initialize(message), false);
+
+                if (jsErrorCode != JsErrorCode::JsErrorScriptCompile)
+                {
+                    CHAR shortFileName[_MAX_PATH];
+                    CHAR ext[_MAX_EXT];
+                    _splitpath_s(fileName, nullptr, 0, nullptr, 0, shortFileName, _countof(shortFileName), ext, _countof(ext));
+
+                    if (metaData != JS_INVALID_REFERENCE)
+                    {
+                        JsPropertyIdRef linePropertyId = JS_INVALID_REFERENCE;
+                        JsValueRef lineProperty = JS_INVALID_REFERENCE;
+
+                        JsPropertyIdRef columnPropertyId = JS_INVALID_REFERENCE;
+                        JsValueRef columnProperty = JS_INVALID_REFERENCE;
+                        
+                        int line;
+                        int column;
+                        
+                        IfJsrtErrorFail(CreatePropertyIdFromString("line", &linePropertyId), false);
+                        IfJsrtErrorFail(ChakraRTInterface::JsGetProperty(metaData, linePropertyId, &lineProperty), false);
+                        IfJsrtErrorFail(ChakraRTInterface::JsNumberToInt(lineProperty, &line), false);
+
+                        IfJsrtErrorFail(CreatePropertyIdFromString("column", &columnPropertyId), false);
+                        IfJsrtErrorFail(ChakraRTInterface::JsGetProperty(metaData, columnPropertyId, &columnProperty), false);
+                        IfJsrtErrorFail(ChakraRTInterface::JsNumberToInt(columnProperty, &column), false);
+                        fwprintf(stderr, _u("%ls\n        at code (%S%S:%d:%d)\n"),
+                            errorMessage.GetWideString(), shortFileName, ext, line + 1, column + 1);
+                    }
+                    else
+                    {
+                        fwprintf(stderr, _u("%ls\n\tat code (%S%S:\?\?:\?\?)\n"), errorMessage.GetWideString(), shortFileName, ext);
+                    }
+                    return true;
+                }
+            }
 
             if (jsErrorCode == JsErrorCode::JsErrorScriptCompile)
             {

+ 11 - 10
bin/ch/ch.cpp

@@ -1,5 +1,6 @@
 //-------------------------------------------------------------------------------------------------------
 // Copyright (C) Microsoft. All rights reserved.
+// Copyright (c) 2021 ChakraCore Project Contributors. All rights reserved.
 // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
 //-------------------------------------------------------------------------------------------------------
 #include "stdafx.h"
@@ -398,6 +399,10 @@ HRESULT RunScript(const char* fileName, LPCSTR fileContents, size_t fileLength,
         IfJsErrorFailLogLabel(ChakraRTInterface::JsCreateString(fullPath,
             strlen(fullPath), &fname), ErrorRunFinalize);
 
+        // memory management for serialized script case - need to define these here
+        SerializedCallbackInfo serializedCallbackInfo;
+        serializedCallbackInfo.freeingHandled = true;
+
         if (bufferValue != nullptr)
         {
             if (fileContents == nullptr)
@@ -414,7 +419,6 @@ HRESULT RunScript(const char* fileName, LPCSTR fileContents, size_t fileLength,
             else // fileContents != nullptr
             {
                 // Memory management is a little more complex here
-                SerializedCallbackInfo serializedCallbackInfo;
                 serializedCallbackInfo.scriptBody = (void*)fileContents;
                 serializedCallbackInfo.scriptBodyFinalizeCallback = fileContentsFinalizeCallback;
                 serializedCallbackInfo.freeingHandled = false;
@@ -427,15 +431,6 @@ HRESULT RunScript(const char* fileName, LPCSTR fileContents, size_t fileLength,
                     // Use source ptr as sourceContext
                     fname,
                     nullptr /*result*/);
-                // Now that we're down here, we can free the fileContents if they weren't sent into
-                // a GC-managed object.
-                if (!serializedCallbackInfo.freeingHandled)
-                {
-                    if (fileContentsFinalizeCallback != nullptr)
-                    {
-                        fileContentsFinalizeCallback((void*)fileContents);
-                    }
-                }
             }
         }
         else if (parserStateCache != nullptr)
@@ -520,6 +515,12 @@ HRESULT RunScript(const char* fileName, LPCSTR fileContents, size_t fileLength,
                 IfFailGo(messageQueue->ProcessAll(fileName));
             } while(!messageQueue->IsEmpty());
         }
+
+        // free the source for the serialized script case if it's not been handed to a managed object
+        if (!serializedCallbackInfo.freeingHandled && fileContentsFinalizeCallback != nullptr)
+        {
+            fileContentsFinalizeCallback((void*)fileContents);
+        }
     }
 
     if(false)

+ 2 - 0
bin/ch/stdafx.h

@@ -1,5 +1,6 @@
 //-------------------------------------------------------------------------------------------------------
 // Copyright (C) Microsoft. All rights reserved.
+// Copyright (c) 2021 ChakraCore Project Contributors. All rights reserved.
 // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
 //-------------------------------------------------------------------------------------------------------
 #pragma once
@@ -197,6 +198,7 @@ public:
 
     JsErrorCode Initialize(JsValueRef value)
     {
+        errorCode = JsNoError;
         JsValueRef strValue;
         JsValueType type;
         ChakraRTInterface::JsGetValueType(value, &type);

+ 4 - 0
test/Error/exceptionInErrorToString.baseline

@@ -0,0 +1,4 @@
+CALLED toString
+ERROR attempting to coerce error to string, using alternate handler
+'a' is not defined
+        at code (exceptionInErrorToString.js:12:1)

+ 12 - 0
test/Error/exceptionInErrorToString.js

@@ -0,0 +1,12 @@
+//-------------------------------------------------------------------------------------------------------
+// Copyright (C) Microsoft. All rights reserved.
+// Copyright (c) 2021 ChakraCore Project Contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
+//-------------------------------------------------------------------------------------------------------
+
+
+// Print sensible output for crashing when Error.toString is overwritten
+// See https://github.com/chakra-core/ChakraCore/issues/6567 for more detail
+
+ReferenceError.prototype.toString = function ( ) { print("CALLED toString"); return { toString () { return "hi"}};}
+a.b();

+ 6 - 0
test/Error/rlexe.xml

@@ -179,4 +179,10 @@
       <files>errorPrototypetoString.js</files>
     </default>
   </test>
+  <test>
+    <default>
+      <files>exceptionInErrorToString.js</files>
+      <baseline>exceptionInErrorToString.baseline</baseline>
+    </default>
+  </test>
 </regress-exe>