Commit b88b3edb authored by mkwst@chromium.org's avatar mkwst@chromium.org

Trigger `window.onerror` only for exceptions thrown in the same world.

This patch addresses half of crbug.com/225513 by grabbing the currently
active DOMWrapperWorld when creating ErrorEvent objects, and checking
that we're still in the same world when triggering `window.onerror`
handlers.

The next step will be to adjust event dispatching to ensure that 'error'
event listeners only trigger in the same world as the exception. I'll address
that in a separate patch; this patch adds several FAILing test results to make
that gap clear.

BUG=225513

Review URL: https://chromiumcodereview.appspot.com/21071003

git-svn-id: svn://svn.chromium.org/blink/trunk@157376 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent d736905e
Test that window.onerror and "error" event listeners from main world are invoked for uncaught exceptions in scripts running in isolate worlds as well as for exceptions in the main world.
Test that window.onerror and "error" event listeners from main world are not invoked for uncaught exceptions in scripts running in isolate worlds, but only for exceptions in the main world.
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
window.onerror: "Uncaught Error: Error in isolated world inline script." at (Line: 11, Column: 18)
No stack trace.
Returning 'true': the error should not be reported in the console as an unhandled exception.
Handling 'error' event (phase 2): "Uncaught Error: Error in isolated world inline script." at :11
No stack trace.
PASS eventPassedToTheErrorListener is window.event
......@@ -17,21 +11,21 @@ Calling e.preventDefault(): the error should not be reported in the console as a
window.onerror: "Uncaught Error: Error in main world inline script." at window-onerror-isolatedworld-01.html (Line: 33, Column: 18)
window.onerror: "Uncaught Error: Error in main world inline script." at window-onerror-isolatedworld-01.html (Line: 52, Column: 18)
Stack Trace:
Error: Error in main world inline script.
at exceptions window-onerror-isolatedworld-01.html:33:19
at window-onerror-isolatedworld-01.html:39:9
at exceptions window-onerror-isolatedworld-01.html:52:19
at window-onerror-isolatedworld-01.html:58:9
Returning 'true': the error should not be reported in the console as an unhandled exception.
Handling 'error' event (phase 2): "Uncaught Error: Error in main world inline script." at window-onerror-isolatedworld-01.html:33
Handling 'error' event (phase 2): "Uncaught Error: Error in main world inline script." at window-onerror-isolatedworld-01.html:52
Stack Trace:
Error: Error in main world inline script.
at exceptions window-onerror-isolatedworld-01.html:33:19
at window-onerror-isolatedworld-01.html:39:9
at exceptions window-onerror-isolatedworld-01.html:52:19
at window-onerror-isolatedworld-01.html:58:9
PASS eventPassedToTheErrorListener is window.event
PASS eventCurrentTarget is window
......@@ -39,12 +33,6 @@ Calling e.preventDefault(): the error should not be reported in the console as a
window.onerror: "Uncaught Error: Error in isolated world load handler." at (Line: 8, Column: 22)
No stack trace.
Returning 'true': the error should not be reported in the console as an unhandled exception.
Handling 'error' event (phase 2): "Uncaught Error: Error in isolated world load handler." at :8
No stack trace.
PASS eventPassedToTheErrorListener is window.event
......@@ -53,19 +41,19 @@ Calling e.preventDefault(): the error should not be reported in the console as a
window.onerror: "Uncaught Error: Error in main world load handler." at window-onerror-isolatedworld-01.html (Line: 30, Column: 22)
window.onerror: "Uncaught Error: Error in main world load handler." at window-onerror-isolatedworld-01.html (Line: 49, Column: 22)
Stack Trace:
Error: Error in main world load handler.
at window-onerror-isolatedworld-01.html:30:23
at window-onerror-isolatedworld-01.html:49:23
Returning 'true': the error should not be reported in the console as an unhandled exception.
Handling 'error' event (phase 2): "Uncaught Error: Error in main world load handler." at window-onerror-isolatedworld-01.html:30
Handling 'error' event (phase 2): "Uncaught Error: Error in main world load handler." at window-onerror-isolatedworld-01.html:49
Stack Trace:
Error: Error in main world load handler.
at window-onerror-isolatedworld-01.html:30:23
at window-onerror-isolatedworld-01.html:49:23
PASS eventPassedToTheErrorListener is window.event
PASS eventCurrentTarget is window
......@@ -73,12 +61,7 @@ Calling e.preventDefault(): the error should not be reported in the console as a
window.onerror: "Uncaught Error: Error in isolated world setTimeout callback." at (Line: 6, Column: 26)
No stack trace.
Returning 'true': the error should not be reported in the console as an unhandled exception.
FAIL Only main-world exceptions should be caught by ErrorEvent listeners.
Handling 'error' event (phase 2): "Uncaught Error: Error in isolated world setTimeout callback." at :6
No stack trace.
PASS eventPassedToTheErrorListener is window.event
......@@ -87,19 +70,20 @@ Calling e.preventDefault(): the error should not be reported in the console as a
window.onerror: "Uncaught Error: Error in main world setTimeout callback." at window-onerror-isolatedworld-01.html (Line: 28, Column: 26)
FAIL Only main-world exceptions should be caught by ErrorEvent listeners.
window.onerror: "Uncaught Error: Error in main world setTimeout callback." at window-onerror-isolatedworld-01.html (Line: 47, Column: 26)
Stack Trace:
Error: Error in main world setTimeout callback.
at window-onerror-isolatedworld-01.html:28:27
at window-onerror-isolatedworld-01.html:47:27
Returning 'true': the error should not be reported in the console as an unhandled exception.
Handling 'error' event (phase 2): "Uncaught Error: Error in main world setTimeout callback." at window-onerror-isolatedworld-01.html:28
Handling 'error' event (phase 2): "Uncaught Error: Error in main world setTimeout callback." at window-onerror-isolatedworld-01.html:47
Stack Trace:
Error: Error in main world setTimeout callback.
at window-onerror-isolatedworld-01.html:28:27
at window-onerror-isolatedworld-01.html:47:27
PASS eventPassedToTheErrorListener is window.event
PASS eventCurrentTarget is window
......@@ -107,6 +91,7 @@ Calling e.preventDefault(): the error should not be reported in the console as a
FAIL Only main-world exceptions should be caught by ErrorEvent listeners.
PASS successfullyParsed is true
TEST COMPLETE
......
......@@ -10,15 +10,34 @@
</head>
<body>
<script>
description('Test that window.onerror and "error" event listeners from main world are invoked for uncaught exceptions in scripts running in isolate worlds as well as for exceptions in the main world.');
description('Test that window.onerror and "error" event listeners from main world are not invoked for uncaught exceptions in scripts running in isolate worlds, but only for exceptions in the main world.');
function callback(errorsHandled) {
if (errorsHandled === 12)
var onerrorsHandled = 0;
function onErrorCallback(errorsHandled) {
onerrorsHandled++;
if (onerrorsHandled > 3)
testFailed("Only main-world exceptions should be caught by onerror handlers.");
// FIXME: This should be 6 once we correctly handle 'error' event dispatch for worlds: crbug.com/225513
if (errorsHandled === 9)
finishJSTest();
}
var errorEventsHandled = 0;
function errorEventCallback(errorsHandled) {
errorEventsHandled++;
if (errorEventsHandled > 3) {
// FIXME: This currently fails. We need to correctly handle 'error' event dispatch for worlds: crbug.com/225513
testFailed("Only main-world exceptions should be caught by ErrorEvent listeners.");
}
// FIXME: This should be 6 once we correctly handle 'error' event dispatch for worlds: crbug.com/225513
if (errorsHandled === 9)
finishJSTest();
}
dumpOnErrorArgumentValuesAndReturn(true, callback);
dumpErrorEventAndPreventDefault(callback);
dumpOnErrorArgumentValuesAndReturn(true, onErrorCallback);
dumpErrorEventAndPreventDefault(errorEventCallback);
var exceptions = function(worldType)
{
......
......@@ -4,15 +4,11 @@ isolated world window.onerror: Uncaught Error: Error in isolated world inline sc
Error object present!
isolated world error event listener: Uncaught Error: Error in isolated world inline script. at :, Line: 41
Error object present!
isolated world window.onerror: Uncaught Error: Error in main world inline script. at window-onerror-isolatedworld-02.html, Line: 30, Column: 18
No error object present!
isolated world error event listener: Uncaught Error: Error in main world inline script. at window-onerror-isolatedworld-02.html:, Line: 30
No error object present!
isolated world window.onerror: Uncaught Error: Error in isolated world load handler. at , Line: 38, Column: 22
Error object present!
isolated world error event listener: Uncaught Error: Error in isolated world load handler. at :, Line: 38
Error object present!
isolated world window.onerror: Uncaught Error: Error in main world load handler. at window-onerror-isolatedworld-02.html, Line: 27, Column: 22
No error object present!
isolated world error event listener: Uncaught Error: Error in main world load handler. at window-onerror-isolatedworld-02.html:, Line: 27
No error object present!
......@@ -55,8 +55,12 @@ v8::Local<v8::Value> V8ErrorHandler::callListenerFunction(ScriptExecutionContext
return V8EventListener::callListenerFunction(context, jsEvent, event);
ErrorEvent* errorEvent = static_cast<ErrorEvent*>(event);
v8::Local<v8::Object> listener = getListenerObject(context);
v8::Isolate* isolate = toV8Context(context, world())->GetIsolate();
if (errorEvent->world() && errorEvent->world() != world())
return v8::Null(isolate);
v8::Local<v8::Object> listener = getListenerObject(context);
v8::Local<v8::Value> returnValue;
if (!listener.IsEmpty() && listener->IsFunction()) {
v8::Local<v8::Function> callFunction = v8::Local<v8::Function>::Cast(listener);
......
......@@ -102,7 +102,7 @@ static void messageHandlerInMainThread(v8::Handle<v8::Message> message, v8::Hand
String resource = shouldUseDocumentURL ? firstWindow->document()->url() : toWebCoreString(resourceName);
AccessControlStatus corsStatus = message->IsSharedCrossOrigin() ? SharableCrossOrigin : NotSharableCrossOrigin;
RefPtr<ErrorEvent> event = ErrorEvent::create(errorMessage, resource, message->GetLineNumber(), message->GetStartColumn());
RefPtr<ErrorEvent> event = ErrorEvent::create(errorMessage, resource, message->GetLineNumber(), message->GetStartColumn(), DOMWrapperWorld::current());
if (V8DOMWrapper::isDOMWrapper(data)) {
v8::Handle<v8::Object> obj = v8::Handle<v8::Object>::Cast(data);
WrapperTypeInfo* type = toWrapperTypeInfo(obj);
......@@ -190,7 +190,7 @@ static void messageHandlerInWorker(v8::Handle<v8::Message> message, v8::Handle<v
if (ScriptExecutionContext* context = getScriptExecutionContext()) {
String errorMessage = toWebCoreString(message->Get());
String sourceURL = toWebCoreString(message->GetScriptResourceName());
RefPtr<ErrorEvent> event = ErrorEvent::create(errorMessage, sourceURL, message->GetLineNumber(), message->GetStartColumn());
RefPtr<ErrorEvent> event = ErrorEvent::create(errorMessage, sourceURL, message->GetLineNumber(), message->GetStartColumn(), DOMWrapperWorld::current());
AccessControlStatus corsStatus = message->IsSharedCrossOrigin() ? SharableCrossOrigin : NotSharableCrossOrigin;
V8ErrorHandler::storeExceptionOnErrorEventWrapper(event.get(), data, v8::Isolate::GetCurrent());
......
......@@ -189,11 +189,11 @@ void WorkerScriptController::evaluate(const ScriptSourceCode& sourceCode, RefPtr
if (state.hadException) {
if (errorEvent) {
*errorEvent = m_workerGlobalScope->shouldSanitizeScriptError(state.sourceURL, NotSharableCrossOrigin) ?
ErrorEvent::createSanitizedError() : ErrorEvent::create(state.errorMessage, state.sourceURL, state.lineNumber, state.columnNumber);
ErrorEvent::createSanitizedError(0) : ErrorEvent::create(state.errorMessage, state.sourceURL, state.lineNumber, state.columnNumber, 0);
V8ErrorHandler::storeExceptionOnErrorEventWrapper(errorEvent->get(), state.exception.v8Value(), m_isolate);
} else {
ASSERT(!m_workerGlobalScope->shouldSanitizeScriptError(state.sourceURL, NotSharableCrossOrigin));
RefPtr<ErrorEvent> event = m_errorEventFromImportedScript ? m_errorEventFromImportedScript.release() : ErrorEvent::create(state.errorMessage, state.sourceURL, state.lineNumber, state.columnNumber);
RefPtr<ErrorEvent> event = m_errorEventFromImportedScript ? m_errorEventFromImportedScript.release() : ErrorEvent::create(state.errorMessage, state.sourceURL, state.lineNumber, state.columnNumber, 0);
m_workerGlobalScope->reportException(event, 0, NotSharableCrossOrigin);
}
}
......
......@@ -54,16 +54,18 @@ ErrorEvent::ErrorEvent(const AtomicString& type, const ErrorEventInit& initializ
, m_fileName(initializer.filename)
, m_lineNumber(initializer.lineno)
, m_columnNumber(initializer.colno)
, m_world(DOMWrapperWorld::current())
{
ScriptWrappable::init(this);
}
ErrorEvent::ErrorEvent(const String& message, const String& fileName, unsigned lineNumber, unsigned columnNumber)
ErrorEvent::ErrorEvent(const String& message, const String& fileName, unsigned lineNumber, unsigned columnNumber, PassRefPtr<DOMWrapperWorld> world)
: Event(eventNames().errorEvent, false, true)
, m_sanitizedMessage(message)
, m_fileName(fileName)
, m_lineNumber(lineNumber)
, m_columnNumber(columnNumber)
, m_world(world)
{
ScriptWrappable::init(this);
}
......
......@@ -31,7 +31,9 @@
#ifndef ErrorEvent_h
#define ErrorEvent_h
#include "bindings/v8/DOMWrapperWorld.h"
#include "core/dom/Event.h"
#include "wtf/RefPtr.h"
#include "wtf/text/WTFString.h"
namespace WebCore {
......@@ -51,17 +53,17 @@ public:
{
return adoptRef(new ErrorEvent);
}
static PassRefPtr<ErrorEvent> create(const String& message, const String& fileName, unsigned lineNumber, unsigned columnNumber)
static PassRefPtr<ErrorEvent> create(const String& message, const String& fileName, unsigned lineNumber, unsigned columnNumber, PassRefPtr<DOMWrapperWorld> world)
{
return adoptRef(new ErrorEvent(message, fileName, lineNumber, columnNumber));
return adoptRef(new ErrorEvent(message, fileName, lineNumber, columnNumber, world));
}
static PassRefPtr<ErrorEvent> create(const AtomicString& type, const ErrorEventInit& initializer)
{
return adoptRef(new ErrorEvent(type, initializer));
}
static PassRefPtr<ErrorEvent> createSanitizedError()
static PassRefPtr<ErrorEvent> createSanitizedError(PassRefPtr<DOMWrapperWorld> world)
{
return adoptRef(new ErrorEvent("Script error.", String(), 0, 0));
return adoptRef(new ErrorEvent("Script error.", String(), 0, 0, world));
}
virtual ~ErrorEvent();
......@@ -76,11 +78,13 @@ public:
virtual const AtomicString& interfaceName() const;
PassRefPtr<DOMWrapperWorld> world() const { return m_world; }
void setUnsanitizedMessage(const String&);
private:
ErrorEvent();
ErrorEvent(const String& message, const String& fileName, unsigned lineNumber, unsigned columnNumber);
ErrorEvent(const String& message, const String& fileName, unsigned lineNumber, unsigned columnNumber, PassRefPtr<DOMWrapperWorld>);
ErrorEvent(const AtomicString&, const ErrorEventInit&);
String m_unsanitizedMessage;
......@@ -88,6 +92,8 @@ private:
String m_fileName;
unsigned m_lineNumber;
unsigned m_columnNumber;
RefPtr<DOMWrapperWorld> m_world;
};
} // namespace WebCore
......
......@@ -241,7 +241,7 @@ bool ScriptExecutionContext::dispatchErrorEvent(PassRefPtr<ErrorEvent> event, Ac
RefPtr<ErrorEvent> errorEvent = event;
if (shouldSanitizeScriptError(errorEvent->filename(), corsStatus))
errorEvent = ErrorEvent::createSanitizedError();
errorEvent = ErrorEvent::createSanitizedError(errorEvent->world());
ASSERT(!m_inDispatchErrorEvent);
m_inDispatchErrorEvent = true;
......
......@@ -138,7 +138,7 @@ private:
// We don't bother checking the askedToTerminate() flag here, because exceptions should *always* be reported even if the thread is terminated.
// This is intentionally different than the behavior in MessageWorkerTask, because terminated workers no longer deliver messages (section 4.6 of the WebWorker spec), but they do report exceptions.
RefPtr<ErrorEvent> event = ErrorEvent::create(m_errorMessage, m_sourceURL, m_lineNumber, m_columnNumber);
RefPtr<ErrorEvent> event = ErrorEvent::create(m_errorMessage, m_sourceURL, m_lineNumber, m_columnNumber, 0);
bool errorHandled = !workerObject->dispatchEvent(event);
if (!errorHandled)
context->reportException(event, 0, NotSharableCrossOrigin);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment