зеркало из https://github.com/mozilla/gecko-dev.git
Backed out changeset 87f0c3b8a317 (bug 1810582) for bustages on nsConsoleService.cpp . CLOSED TREE
This commit is contained in:
Родитель
400e875b6d
Коммит
d6464873cf
|
@ -23,8 +23,6 @@
|
|||
#include "nsProxyRelease.h"
|
||||
#include "nsIScriptError.h"
|
||||
#include "nsISupportsPrimitives.h"
|
||||
#include "nsGlobalWindowInner.h"
|
||||
#include "js/friend/ErrorMessages.h"
|
||||
#include "mozilla/dom/WindowGlobalParent.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/dom/BrowserParent.h"
|
||||
|
@ -396,53 +394,6 @@ nsresult nsConsoleService::LogMessageWithMode(
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
// See nsIConsoleService.idl for more info about this method
|
||||
NS_IMETHODIMP
|
||||
nsConsoleService::CallFunctionAndLogException(
|
||||
JS::Handle<JS::Value> targetGlobal, JS::HandleValue function, JSContext* cx,
|
||||
JS::MutableHandleValue retval) {
|
||||
if (!targetGlobal.isObject() || !function.isObject()) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
JS::Rooted<JS::Realm*> contextRealm(cx, JS::GetCurrentRealmOrNull(cx));
|
||||
if (!contextRealm) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> global(
|
||||
cx, js::CheckedUnwrapDynamic(&targetGlobal.toObject(), cx));
|
||||
if (!global) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
// Use AutoJSAPI in order to trigger AutoJSAPI::ReportException
|
||||
// which will do most of the work required for this function.
|
||||
//
|
||||
// We only have to pick the right global for which we want to flag
|
||||
// the exception against.
|
||||
AutoJSAPI jsapi;
|
||||
if (!jsapi.Init(global)) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
JSContext* ccx = jsapi.cx();
|
||||
|
||||
// AutoJSAPI picks `targetGlobal` as execution compartment
|
||||
// whereas we expect to run `function` from the callsites compartment.
|
||||
JSAutoRealm ar(ccx, JS::GetRealmGlobalOrNull(contextRealm));
|
||||
|
||||
JS::RootedValue funVal(ccx, function);
|
||||
if (!JS_WrapValue(ccx, &funVal)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
if (!JS_CallFunctionValue(ccx, nullptr, funVal, JS::HandleValueArray::empty(),
|
||||
retval)) {
|
||||
return NS_ERROR_XPC_JAVASCRIPT_ERROR;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void nsConsoleService::CollectCurrentListeners(
|
||||
nsCOMArray<nsIConsoleListener>& aListeners) {
|
||||
MutexAutoLock lock(mLock);
|
||||
|
|
|
@ -13,18 +13,6 @@ interface nsIConsoleService : nsISupports
|
|||
{
|
||||
void logMessage(in nsIConsoleMessage message);
|
||||
|
||||
// This helper function executes `function` and redirects any exception
|
||||
// that may be thrown while running it to the DevTools Console currently
|
||||
// debugging `targetGlobal`.
|
||||
//
|
||||
// This helps flag the nsIScriptError with a particular innerWindowID
|
||||
// which is especially useful for WebExtension content scripts
|
||||
// where script are running in a Sandbox whose prototype is the content window.
|
||||
// We expect content script exception to be flaged with the content window
|
||||
// innerWindowID in order to appear in the tab's DevTools.
|
||||
[implicit_jscontext]
|
||||
jsval callFunctionAndLogException(in jsval targetGlobal, in jsval function);
|
||||
|
||||
// This is a variant of LogMessage which allows the caller to determine
|
||||
// if the message should be output to an OS-specific log. This is used on
|
||||
// B2G to control whether the message is logged to the android log or not.
|
||||
|
|
|
@ -1,265 +0,0 @@
|
|||
let lastMessage;
|
||||
const consoleListener = {
|
||||
observe(message) {
|
||||
dump(" >> new message: " + message.errorMessage + "\n");
|
||||
lastMessage = message;
|
||||
},
|
||||
};
|
||||
Services.console.registerListener(consoleListener);
|
||||
|
||||
// The Console Service notifies its listener after one event loop cycle.
|
||||
// So wait for one tick after each action dispatching a message/error to the service.
|
||||
function waitForATick() {
|
||||
return new Promise(resolve => Services.tm.dispatchToMainThread(resolve));
|
||||
}
|
||||
|
||||
add_task(async function customScriptError() {
|
||||
const scriptError = Cc["@mozilla.org/scripterror;1"].createInstance(
|
||||
Ci.nsIScriptError
|
||||
);
|
||||
scriptError.init(
|
||||
"foo",
|
||||
"file.js",
|
||||
null,
|
||||
1,
|
||||
2,
|
||||
Ci.nsIScriptError.warningFlag,
|
||||
"some javascript"
|
||||
);
|
||||
Services.console.logMessage(scriptError);
|
||||
|
||||
await waitForATick();
|
||||
|
||||
Assert.equal(
|
||||
lastMessage,
|
||||
scriptError,
|
||||
"We receive the exact same nsIScriptError object"
|
||||
);
|
||||
|
||||
Assert.equal(lastMessage.errorMessage, "foo");
|
||||
Assert.equal(lastMessage.sourceName, "file.js");
|
||||
Assert.equal(lastMessage.lineNumber, 1);
|
||||
Assert.equal(lastMessage.columnNumber, 2);
|
||||
Assert.equal(lastMessage.flags, Ci.nsIScriptError.warningFlag);
|
||||
Assert.equal(lastMessage.category, "some javascript");
|
||||
|
||||
Assert.equal(
|
||||
lastMessage.stack,
|
||||
undefined,
|
||||
"Custom nsIScriptError object created from JS can't convey any stack"
|
||||
);
|
||||
});
|
||||
|
||||
add_task(async function callFunctionAndLogExceptionWithChromeGlobal() {
|
||||
try {
|
||||
Services.console.callFunctionAndLogException(globalThis, function () {
|
||||
throw new Error("custom exception");
|
||||
});
|
||||
Assert.fail("callFunctionAndLogException should throw");
|
||||
} catch (e) {
|
||||
Assert.equal(
|
||||
e.name,
|
||||
"NS_ERROR_XPC_JAVASCRIPT_ERROR",
|
||||
"callFunctionAndLogException thrown"
|
||||
);
|
||||
}
|
||||
|
||||
await waitForATick();
|
||||
|
||||
Assert.ok(!!lastMessage, "Got the message");
|
||||
Assert.ok(
|
||||
lastMessage instanceof Ci.nsIScriptError,
|
||||
"This is a nsIScriptError"
|
||||
);
|
||||
|
||||
Assert.equal(lastMessage.errorMessage, "Error: custom exception");
|
||||
Assert.equal(lastMessage.sourceName, _TEST_FILE);
|
||||
Assert.equal(lastMessage.lineNumber, 56);
|
||||
Assert.equal(lastMessage.columnNumber, 13);
|
||||
Assert.equal(lastMessage.flags, Ci.nsIScriptError.errorFlag);
|
||||
Assert.equal(lastMessage.category, "chrome javascript");
|
||||
Assert.ok(lastMessage.stack, "It has a stack");
|
||||
Assert.equal(lastMessage.stack.source, _TEST_FILE);
|
||||
Assert.equal(lastMessage.stack.line, 56);
|
||||
Assert.equal(lastMessage.stack.column, 13);
|
||||
Assert.ok(!!lastMessage.stack.parent, "stack has a parent frame");
|
||||
Assert.equal(
|
||||
lastMessage.innerWindowID,
|
||||
0,
|
||||
"The message isn't bound to any WindowGlobal"
|
||||
);
|
||||
});
|
||||
|
||||
add_task(async function callFunctionAndLogExceptionWithContentGlobal() {
|
||||
const window = createContentWindow();
|
||||
try {
|
||||
Services.console.callFunctionAndLogException(window, function () {
|
||||
throw new Error("another custom exception");
|
||||
});
|
||||
Assert.fail("callFunctionAndLogException should throw");
|
||||
} catch (e) {
|
||||
Assert.equal(
|
||||
e.name,
|
||||
"NS_ERROR_XPC_JAVASCRIPT_ERROR",
|
||||
"callFunctionAndLogException thrown"
|
||||
);
|
||||
}
|
||||
|
||||
await waitForATick();
|
||||
|
||||
Assert.ok(!!lastMessage, "Got the message");
|
||||
Assert.ok(
|
||||
lastMessage instanceof Ci.nsIScriptError,
|
||||
"This is a nsIScriptError"
|
||||
);
|
||||
|
||||
Assert.equal(lastMessage.errorMessage, "Error: another custom exception");
|
||||
Assert.equal(lastMessage.sourceName, _TEST_FILE);
|
||||
Assert.equal(lastMessage.lineNumber, 97);
|
||||
Assert.equal(lastMessage.columnNumber, 13);
|
||||
Assert.equal(lastMessage.flags, Ci.nsIScriptError.errorFlag);
|
||||
Assert.equal(lastMessage.category, "content javascript");
|
||||
Assert.ok(lastMessage.stack, "It has a stack");
|
||||
Assert.equal(lastMessage.stack.source, _TEST_FILE);
|
||||
Assert.equal(lastMessage.stack.line, 97);
|
||||
Assert.equal(lastMessage.stack.column, 13);
|
||||
Assert.ok(!!lastMessage.stack.parent, "stack has a parent frame");
|
||||
Assert.ok(
|
||||
!!window.windowGlobalChild.innerWindowId,
|
||||
"The window has a innerWindowId"
|
||||
);
|
||||
Assert.equal(
|
||||
lastMessage.innerWindowID,
|
||||
window.windowGlobalChild.innerWindowId,
|
||||
"The message is bound to the content window"
|
||||
);
|
||||
});
|
||||
|
||||
add_task(async function callFunctionAndLogExceptionForContentScriptSandboxes() {
|
||||
const { sandbox, window } = createContentScriptSandbox();
|
||||
Cu.evalInSandbox(
|
||||
`function foo() { throw new Error("sandbox exception"); }`,
|
||||
sandbox,
|
||||
null,
|
||||
"sandbox-file.js",
|
||||
1,
|
||||
0
|
||||
);
|
||||
try {
|
||||
Services.console.callFunctionAndLogException(window, sandbox.foo);
|
||||
Assert.fail("callFunctionAndLogException should throw");
|
||||
} catch (e) {
|
||||
Assert.equal(
|
||||
e.name,
|
||||
"NS_ERROR_XPC_JAVASCRIPT_ERROR",
|
||||
"callFunctionAndLogException thrown"
|
||||
);
|
||||
}
|
||||
|
||||
await waitForATick();
|
||||
|
||||
Assert.ok(!!lastMessage, "Got the message");
|
||||
// Note that it is important to "instanceof" in order to expose the nsIScriptError attributes.
|
||||
Assert.ok(
|
||||
lastMessage instanceof Ci.nsIScriptError,
|
||||
"This is a nsIScriptError"
|
||||
);
|
||||
|
||||
Assert.equal(lastMessage.errorMessage, "Error: sandbox exception");
|
||||
Assert.equal(lastMessage.sourceName, "sandbox-file.js");
|
||||
Assert.equal(lastMessage.lineNumber, 1);
|
||||
Assert.equal(lastMessage.columnNumber, 24);
|
||||
Assert.equal(lastMessage.flags, Ci.nsIScriptError.errorFlag);
|
||||
Assert.equal(lastMessage.category, "content javascript");
|
||||
Assert.ok(lastMessage.stack, "It has a stack");
|
||||
Assert.equal(lastMessage.stack.source, "sandbox-file.js");
|
||||
Assert.equal(lastMessage.stack.line, 1);
|
||||
Assert.equal(lastMessage.stack.column, 24);
|
||||
Assert.ok(!!lastMessage.stack.parent, "stack has a parent frame");
|
||||
Assert.ok(
|
||||
!!window.windowGlobalChild.innerWindowId,
|
||||
"The sandbox's prototype is a window and has a innerWindowId"
|
||||
);
|
||||
Assert.equal(
|
||||
lastMessage.innerWindowID,
|
||||
window.windowGlobalChild.innerWindowId,
|
||||
"The message is bound to the sandbox's prototype WindowGlobal"
|
||||
);
|
||||
});
|
||||
|
||||
add_task(
|
||||
async function callFunctionAndLogExceptionForContentScriptSandboxesWrappedInChrome() {
|
||||
const { sandbox, window } = createContentScriptSandbox();
|
||||
Cu.evalInSandbox(
|
||||
`function foo() { throw new Error("sandbox exception"); }`,
|
||||
sandbox,
|
||||
null,
|
||||
"sandbox-file.js",
|
||||
1,
|
||||
0
|
||||
);
|
||||
try {
|
||||
Services.console.callFunctionAndLogException(window, function () {
|
||||
sandbox.foo();
|
||||
});
|
||||
Assert.fail("callFunctionAndLogException should throw");
|
||||
} catch (e) {
|
||||
Assert.equal(
|
||||
e.name,
|
||||
"NS_ERROR_XPC_JAVASCRIPT_ERROR",
|
||||
"callFunctionAndLogException thrown"
|
||||
);
|
||||
}
|
||||
|
||||
await waitForATick();
|
||||
|
||||
Assert.ok(!!lastMessage, "Got the message");
|
||||
// Note that it is important to "instanceof" in order to expose the nsIScriptError attributes.
|
||||
Assert.ok(
|
||||
lastMessage instanceof Ci.nsIScriptError,
|
||||
"This is a nsIScriptError"
|
||||
);
|
||||
|
||||
Assert.ok(
|
||||
!!window.windowGlobalChild.innerWindowId,
|
||||
"The sandbox's prototype is a window and has a innerWindowId"
|
||||
);
|
||||
Assert.equal(
|
||||
lastMessage.innerWindowID,
|
||||
window.windowGlobalChild.innerWindowId,
|
||||
"The message is bound to the sandbox's prototype WindowGlobal"
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
add_task(function teardown() {
|
||||
Services.console.unregisterListener(consoleListener);
|
||||
});
|
||||
|
||||
// We are in xpcshell, so we can't have a real DOM Window as in Firefox
|
||||
// but let's try to have a fake one.
|
||||
function createContentWindow() {
|
||||
const principal =
|
||||
Services.scriptSecurityManager.createContentPrincipalFromOrigin(
|
||||
"http://example.com/"
|
||||
);
|
||||
|
||||
const webnav = Services.appShell.createWindowlessBrowser(false);
|
||||
|
||||
webnav.docShell.createAboutBlankContentViewer(principal, principal);
|
||||
|
||||
return webnav.document.defaultView;
|
||||
}
|
||||
|
||||
// Create a Sandbox as in WebExtension content scripts
|
||||
function createContentScriptSandbox() {
|
||||
const window = createContentWindow();
|
||||
// The sandboxPrototype is the key here in order to
|
||||
// make xpc::SandboxWindowOrNull ignore the sandbox
|
||||
// and instead retrieve its prototype and link the error message
|
||||
// to the window instead of the sandbox.
|
||||
return {
|
||||
sandbox: Cu.Sandbox(window, { sandboxPrototype: window }),
|
||||
window,
|
||||
};
|
||||
}
|
|
@ -19,7 +19,6 @@ skip-if = os == "win"
|
|||
fail-if = os == "android"
|
||||
[test_bug478086.js]
|
||||
[test_bug1434856.js]
|
||||
[test_console_service_callFunctionAndLogException.js]
|
||||
[test_debugger_malloc_size_of.js]
|
||||
[test_file_createUnique.js]
|
||||
[test_file_equality.js]
|
||||
|
|
Загрузка…
Ссылка в новой задаче