Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge pull request #6581 from rhuanjl/printException
Use Exception metadata to print error if Error.toString fails
  • Loading branch information
ppenzin committed Jan 23, 2021
2 parents 51d75d0 + 4bea2b2 commit 978f5ff
Show file tree
Hide file tree
Showing 8 changed files with 104 additions and 12 deletions.
2 changes: 2 additions & 0 deletions 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"
Expand Down Expand Up @@ -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");
Expand Down
4 changes: 4 additions & 0 deletions 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
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -197,6 +199,7 @@ struct JsAPIHooks
JsrtCreateErrorPtr pfJsrtCreateError;
JsrtHasExceptionPtr pfJsrtHasException;
JsrtSetExceptionPtr pfJsrtSetException;
JsrtGetAndClearExceptiopnWithMetadataPtr pfJsrtGetAndClearExceptionWithMetadata;
JsrtGetAndClearExceptiopnPtr pfJsrtGetAndClearException;
JsrtGetRuntimePtr pfJsrtGetRuntime;
JsrtReleasePtr pfJsrtRelease;
Expand Down Expand Up @@ -428,6 +431,7 @@ class ChakraRTInterface
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)); }
Expand Down
65 changes: 63 additions & 2 deletions 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"
Expand Down Expand Up @@ -1766,10 +1767,21 @@ JsValueRef __stdcall WScriptJsrt::GetProxyPropertiesCallback(JsValueRef callee,
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)
Expand All @@ -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)
{
Expand Down
21 changes: 11 additions & 10 deletions 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"
Expand Down Expand Up @@ -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)
Expand All @@ -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;
Expand All @@ -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)
Expand Down Expand Up @@ -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)
Expand Down
2 changes: 2 additions & 0 deletions 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
Expand Down Expand Up @@ -197,6 +198,7 @@ class AutoString

JsErrorCode Initialize(JsValueRef value)
{
errorCode = JsNoError;
JsValueRef strValue;
JsValueType type;
ChakraRTInterface::JsGetValueType(value, &type);
Expand Down
4 changes: 4 additions & 0 deletions 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 changes: 12 additions & 0 deletions 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 changes: 6 additions & 0 deletions test/Error/rlexe.xml
Expand Up @@ -179,4 +179,10 @@
<files>errorPrototypetoString.js</files>
</default>
</test>
<test>
<default>
<files>exceptionInErrorToString.js</files>
<baseline>exceptionInErrorToString.baseline</baseline>
</default>
</test>
</regress-exe>

0 comments on commit 978f5ff

Please sign in to comment.