There are 2 separate issues. One is the error handling for the script execution, which converts the exception to an error report. This could be solved with one of the following, if the script comes from different origin: * (a) Disallow side-effects during the error reporting, in [AutoJSAPI::ReportException](https://searchfox.org/mozilla-central/rev/2c71f1e9b5947612abdc16b64008162c58c1b9d3/dom/script/ScriptSettings.cpp#521), so that the modification in the main global cannot interact with the error details * (b) Use unmodified prototype chain from newly-created realm, so that the modification in the main global doesn't affect the error object * (c) Remove the error message, so that the information doesn't leak to the main global The other is caused by DevTools error reporting, which converts the error object to string. If we take (b) or (c) above, this part is also solved automatically. If we take (a), similar workaround is necessary here. So, (b) or (c) would be safer. (b) requires a new realm, and this will be problematic in term of complexity, performance, and memory consumption. (c) is the simplest solution, but if there's any JS code or library that tries to check error messages, they may break. Historically there had been multiple cases where modifying the error message caused compat issue. So, even if we go this way, we need to make sure the affected case is minimized. Details below: The first issue is happening in the following place, where the script evaluation fails and it's trying to convert the exception to an error report, with side effects allowed: https://searchfox.org/mozilla-central/rev/2c71f1e9b5947612abdc16b64008162c58c1b9d3/dom/script/ScriptLoader.cpp#3226-3227,3229 ```cpp nsresult ScriptLoader::EvaluateScript(nsIGlobalObject* aGlobalObject, ScriptLoadRequest* aRequest) { ... AutoEntryScript aes(aGlobalObject, "EvaluateScript", true); ``` https://searchfox.org/mozilla-central/rev/2c71f1e9b5947612abdc16b64008162c58c1b9d3/dom/script/AutoEntryScript.h#37 ```cpp class MOZ_STACK_CLASS AutoEntryScript : public AutoJSAPI { ``` https://searchfox.org/mozilla-central/rev/2c71f1e9b5947612abdc16b64008162c58c1b9d3/dom/script/ScriptSettings.cpp#276,286 ```cpp AutoJSAPI::~AutoJSAPI() { ... ReportException(); ``` https://searchfox.org/mozilla-central/rev/2c71f1e9b5947612abdc16b64008162c58c1b9d3/dom/script/ScriptSettings.cpp#487,521 ```cpp void AutoJSAPI::ReportException() { ... jsReport.init(cx(), exnStack, JS::ErrorReportBuilder::WithSideEffects)) { ``` https://searchfox.org/mozilla-central/rev/2c71f1e9b5947612abdc16b64008162c58c1b9d3/js/src/jsexn.cpp#487-489,533-534,539 ```cpp bool JS::ErrorReportBuilder::init(JSContext* cx, const JS::ExceptionStack& exnStack, SniffingBehavior sniffingBehavior) { ... if (!reportp && exnObject && sniffingBehavior == WithSideEffects && IsDuckTypedErrorObject(cx, exnObject, &filename_str)) { ... if (JS_GetProperty(cx, exnObject, "name", &val) && val.isString()) { ``` And the second issue is happening in the following place, where the DevTools console is trying to stringify the error: https://searchfox.org/mozilla-central/rev/2c71f1e9b5947612abdc16b64008162c58c1b9d3/devtools/server/actors/webconsole.js#857,907-913 ```js class WebConsoleActor extends Actor { ... evaluateJS(request) { ... const result = this.prepareEvaluationResult( evalInfo, input, request.eager, mapped, request.evalInTracer ); ``` https://searchfox.org/mozilla-central/rev/2c71f1e9b5947612abdc16b64008162c58c1b9d3/devtools/server/actors/webconsole.js#923,972-975 ```js class WebConsoleActor extends Actor { ... prepareEvaluationResult(evalInfo, input, eager, mapped, evalInTracer) { ... errorMessage = DevToolsUtils.callPropertyOnObject( error, "toString" ); ``` https://searchfox.org/mozilla-central/rev/2c71f1e9b5947612abdc16b64008162c58c1b9d3/devtools/shared/DevToolsUtils.js#951,977 ```js function callPropertyOnObject(object, name, ...args) { ... const result = value.call(object, ...args); ``` https://searchfox.org/mozilla-central/rev/2c71f1e9b5947612abdc16b64008162c58c1b9d3/js/src/builtin/Error.js#6,14 ```js function ErrorToString() { ... var name = obj.name; ```
Bug 1960745 Comment 5 Edit History
Note: The actual edited comment in the bug view page will always show the original commenter’s name and original timestamp.
There are 2 separate issues. One is the error handling for the script execution, which converts the exception to an error report. This could be solved with one of the following, if the script comes from different origin: * (a) Disallow side-effects during the error reporting, in [AutoJSAPI::ReportException](https://searchfox.org/mozilla-central/rev/2c71f1e9b5947612abdc16b64008162c58c1b9d3/dom/script/ScriptSettings.cpp#521), so that the modification in the main global cannot interact with the error details * (b) Use unmodified prototype chain from newly-created realm, so that the modification in the main global doesn't affect the error object * (c) Remove the error message, so that the information doesn't leak to the main global The other is caused by DevTools error reporting, which converts the error object to string. If we take (b) or (c) above, this part is also solved automatically. If we take (a), similar workaround is necessary here. So, (b) or (c) would be safer. (b) requires a new realm, and this will be problematic in term of complexity, performance, and memory consumption. (c) is the simplest solution, but if there's any JS code or library that tries to check error messages, they may break. Historically there had been multiple cases where modifying the error message caused compat issue. So, even if we go this way, we need to make sure the affected case is minimized. Details below: The first issue is happening in the following place, where the script evaluation fails and it's trying to convert the exception to an error report, with side effects allowed: https://searchfox.org/mozilla-central/rev/2c71f1e9b5947612abdc16b64008162c58c1b9d3/dom/script/ScriptLoader.cpp#3226-3227,3229 ```cpp nsresult ScriptLoader::EvaluateScript(nsIGlobalObject* aGlobalObject, ScriptLoadRequest* aRequest) { ... AutoEntryScript aes(aGlobalObject, "EvaluateScript", true); ``` https://searchfox.org/mozilla-central/rev/2c71f1e9b5947612abdc16b64008162c58c1b9d3/dom/script/AutoEntryScript.h#37 ```cpp class MOZ_STACK_CLASS AutoEntryScript : public AutoJSAPI { ``` https://searchfox.org/mozilla-central/rev/2c71f1e9b5947612abdc16b64008162c58c1b9d3/dom/script/ScriptSettings.cpp#276,286 ```cpp AutoJSAPI::~AutoJSAPI() { ... ReportException(); ``` https://searchfox.org/mozilla-central/rev/2c71f1e9b5947612abdc16b64008162c58c1b9d3/dom/script/ScriptSettings.cpp#487,521 ```cpp void AutoJSAPI::ReportException() { ... jsReport.init(cx(), exnStack, JS::ErrorReportBuilder::WithSideEffects)) { ``` https://searchfox.org/mozilla-central/rev/2c71f1e9b5947612abdc16b64008162c58c1b9d3/js/src/jsexn.cpp#487-489,505 ```cpp bool JS::ErrorReportBuilder::init(JSContext* cx, const JS::ExceptionStack& exnStack, SniffingBehavior sniffingBehavior) { ... str = ErrorReportToString(cx, exnObject, reportp, sniffingBehavior); ``` https://searchfox.org/mozilla-central/rev/2c71f1e9b5947612abdc16b64008162c58c1b9d3/js/src/jsexn.cpp#441-443,448 ```cpp static JSString* ErrorReportToString(JSContext* cx, HandleObject exn, JSErrorReport* reportp, SniffingBehavior behavior) { ... if (GetPropertyNoException(cx, exn, behavior, cx->names().name, &nameV) && ``` or maybe https://searchfox.org/mozilla-central/rev/2c71f1e9b5947612abdc16b64008162c58c1b9d3/js/src/jsexn.cpp#487-489,533-534,539 ```cpp bool JS::ErrorReportBuilder::init(JSContext* cx, const JS::ExceptionStack& exnStack, SniffingBehavior sniffingBehavior) { ... if (!reportp && exnObject && sniffingBehavior == WithSideEffects && IsDuckTypedErrorObject(cx, exnObject, &filename_str)) { ... if (JS_GetProperty(cx, exnObject, "name", &val) && val.isString()) { ``` And the second issue is happening in the following place, where the DevTools console is trying to stringify the error: https://searchfox.org/mozilla-central/rev/2c71f1e9b5947612abdc16b64008162c58c1b9d3/devtools/server/actors/webconsole.js#857,907-913 ```js class WebConsoleActor extends Actor { ... evaluateJS(request) { ... const result = this.prepareEvaluationResult( evalInfo, input, request.eager, mapped, request.evalInTracer ); ``` https://searchfox.org/mozilla-central/rev/2c71f1e9b5947612abdc16b64008162c58c1b9d3/devtools/server/actors/webconsole.js#923,972-975 ```js class WebConsoleActor extends Actor { ... prepareEvaluationResult(evalInfo, input, eager, mapped, evalInTracer) { ... errorMessage = DevToolsUtils.callPropertyOnObject( error, "toString" ); ``` https://searchfox.org/mozilla-central/rev/2c71f1e9b5947612abdc16b64008162c58c1b9d3/devtools/shared/DevToolsUtils.js#951,977 ```js function callPropertyOnObject(object, name, ...args) { ... const result = value.call(object, ...args); ``` https://searchfox.org/mozilla-central/rev/2c71f1e9b5947612abdc16b64008162c58c1b9d3/js/src/builtin/Error.js#6,14 ```js function ErrorToString() { ... var name = obj.name; ```