+2008-07-20 Oliver Hunt <oliver@apple.com>
+
+ Reviewed by Mark Rowe.
+
+ Add layout test to check correctly handling of exceptions in callback by WebCore.
+ Update existing test results for higher fidelity output.
+
+ * fast/dom/NamedNodeMap-setNamedItem-crash-expected.txt:
+ * fast/js/exceptions-thrown-in-callbacks-expected.txt: Added.
+ * fast/js/exceptions-thrown-in-callbacks.html: Added.
+ * fast/xpath/nsresolver-exception-expected.txt:
+ * fast/xsl/transform-xhr-doc-expected.txt:
+ * http/tests/security/aboutBlank/xss-DENIED-navigate-opener-document-write-expected.txt:
+ * http/tests/security/aboutBlank/xss-DENIED-navigate-opener-javascript-url-expected.txt:
+ * http/tests/security/aboutBlank/xss-DENIED-set-opener-expected.txt:
+ * platform/mac/fast/dynamic/015-expected.txt:
+ * platform/mac/fast/events/updateLayoutForHitTest-expected.txt:
+ * platform/mac/tables/mozilla_expected_failures/bugs/bug92868_1-expected.txt:
+ * platform/mac/tables/mozilla_expected_failures/dom/appendCells1-expected.txt:
+ * platform/mac/tables/mozilla_expected_failures/dom/appendCellsRebuild1-expected.txt:
+ * platform/mac/tables/mozilla_expected_failures/dom/insertTbodyExpand1-expected.txt:
+ * platform/mac/tables/mozilla_expected_failures/dom/insertTbodyRebuild1-expected.txt:
+ * storage/transaction_callback_exception_crash-expected.txt:
+
2008-07-19 Oliver Hunt <oliver@apple.com>
Reviewed by Cameron Zwarich.
-CONSOLE MESSAGE: line 7: NOT_FOUND_ERR: DOM Exception 8
+CONSOLE MESSAGE: line 7: Error: NOT_FOUND_ERR: DOM Exception 8
This passes if it does not crash. (see https://bugs.webkit.org/show_bug.cgi?id=18958)
--- /dev/null
+CONSOLE MESSAGE: line 17: PASS: toString called on exception value thrown from event handler
+CONSOLE MESSAGE: line 23: PASS: toString called on exception value thrown from sql transaction callback
+CONSOLE MESSAGE: line 33: PASS: toString called on exception value thrown from sql error callback
+CONSOLE MESSAGE: line 41: PASS: toString called on exception value thrown from timer
+This test ensures that exceptions are handled correctly by the various callback mechanisms present in WebCore.
--- /dev/null
+This test ensures that exceptions are handled correctly by the various callback mechanisms present in WebCore.
+<script>
+if (window.layoutTestController) {
+ layoutTestController.dumpAsText();
+ layoutTestController.waitUntilDone();
+}
+
+var db = openDatabase("exception-info-test", "1.0", "Test for exception information thrown by callbacks and timers", 1);
+
+function errorObject(msg) {
+ return { message: "FAIL: message incorrectly pulled from thrown object in " + msg,
+ toString: function() {return "PASS: toString called on exception value thrown from " + msg} }
+}
+
+function eventTest() {
+ setTimeout(dbTransactionTest, 0);
+ throw errorObject("event handler");
+}
+
+function dbTransactionTest() {
+ db.transaction(function(tx) {
+ setTimeout(dbStatementTest, 0);
+ throw errorObject("sql transaction callback");
+ });
+}
+
+function dbStatementTest() {
+ db.transaction(
+ function(tx) {
+ tx.executeSql("I am bogus syntax", [], function() {
+ }, function(tx, error) {
+ setTimeout(timerTest, 0);
+ throw errorObject("sql error callback");
+ });
+ });
+}
+
+function timerTest() {
+ if (window.layoutTestController)
+ setTimeout("layoutTestController.notifyDone()", 0);
+ throw errorObject("timer");
+}
+
+window.onload = eventTest;
+</script>
+
-CONSOLE MESSAGE: line 14: this is an exception
+CONSOLE MESSAGE: line 14: Error: this is an exception
SUCCESS
-CONSOLE MESSAGE: line 20: Result of expression 'doc' [undefined] is not an object.
+CONSOLE MESSAGE: line 20: TypeError: Result of expression 'doc' [undefined] is not an object.
Test for bug 10313: xsl:import doesn't work in stylesheets loaded via XMLHttpRequest.
It's nice that this hasn't crashed, but the XSL transformation has failed.
CONSOLE MESSAGE: line 1: Unsafe JavaScript attempt to access frame with URL http://localhost:8000/security/resources/innocent-victim-with-notify.html from frame with URL about:blank. Domains, protocols and ports must match.
-CONSOLE MESSAGE: line 1: Result of expression 'target.document' [undefined] is not an object.
+CONSOLE MESSAGE: line 1: TypeError: Result of expression 'target.document' [undefined] is not an object.
This page opens a window to "", injects malicious code, and then navigates its opener to the victim. The opened window then tries to scripts its opener after document.writeing a new document.
Code injected into window:
<script>document.write('<script>function write(target, message) { target.document.body.innerHTML = message; }setTimeout(function() {write(window.opener, \'FAIL: XSS was allowed.\');}, 100);setTimeout(function() {write(window.opener.top.frames[1], \'SUCCESS: Window remained in original SecurityOrigin.\');}, 200);setTimeout(function() { if (window.layoutTestController) layoutTestController.globalFlag = true; }, 300);<\/script>');</script>
CONSOLE MESSAGE: line 1: Unsafe JavaScript attempt to access frame with URL http://localhost:8000/security/resources/innocent-victim-with-notify.html from frame with URL http://127.0.0.1:8000/security/aboutBlank/xss-DENIED-navigate-opener-javascript-url.html. Domains, protocols and ports must match.
-CONSOLE MESSAGE: line 1: Result of expression 'target.document' [undefined] is not an object.
+CONSOLE MESSAGE: line 1: TypeError: Result of expression 'target.document' [undefined] is not an object.
This page opens a window to "", injects malicious code, and then navigates its opener to the victim. The opened window then tries to scripts its opener after reloading itself as a javascript URL.
Code injected into window:
<script>window.location = 'javascript:\'<script>function write(target, message) { target.document.body.innerHTML = message; }setTimeout(function() {write(window.opener, \\\'FAIL: XSS was allowed.\\\');}, 100);setTimeout(function() {write(window.opener.top.frames[1], \\\'SUCCESS: Window remained in original SecurityOrigin.\\\');}, 200);setTimeout(function() { if (window.layoutTestController) layoutTestController.globalFlag = true; }, 300);<\\\/script>\''</script>
CONSOLE MESSAGE: line 1: Unsafe JavaScript attempt to access frame with URL http://localhost:8000/security/resources/innocent-victim.html from frame with URL about:blank. Domains, protocols and ports must match.
-CONSOLE MESSAGE: line 1: Result of expression 'target.document' [undefined] is not an object.
+CONSOLE MESSAGE: line 1: TypeError: Result of expression 'target.document' [undefined] is not an object.
This page opens a window to "", injects malicious code, and then uses window.open.call to set its opener to the victim. The opened window then tries to scripts its opener.
Code injected into window:
<script>function write(target, message) { target.document.body.innerHTML = message; }
-CONSOLE MESSAGE: line 16: INDEX_SIZE_ERR: DOM Exception 1
+CONSOLE MESSAGE: line 16: Error: INDEX_SIZE_ERR: DOM Exception 1
layer at (0,0) size 800x600
RenderView at (0,0) size 800x600
layer at (0,0) size 800x600
-CONSOLE MESSAGE: line 36: Result of expression 'triangleSpan.nextSibling.nextSibling.nextSibling.nextSibling' [null] is not an object.
-CONSOLE MESSAGE: line 40: Result of expression 'triangleSpan.nextSibling.nextSibling.nextSibling.nextSibling' [null] is not an object.
-CONSOLE MESSAGE: line 36: Result of expression 'triangleSpan.nextSibling.nextSibling.nextSibling.nextSibling' [null] is not an object.
-CONSOLE MESSAGE: line 40: Result of expression 'triangleSpan.nextSibling.nextSibling.nextSibling.nextSibling' [null] is not an object.
+CONSOLE MESSAGE: line 36: TypeError: Result of expression 'triangleSpan.nextSibling.nextSibling.nextSibling.nextSibling' [null] is not an object.
+CONSOLE MESSAGE: line 40: TypeError: Result of expression 'triangleSpan.nextSibling.nextSibling.nextSibling.nextSibling' [null] is not an object.
+CONSOLE MESSAGE: line 36: TypeError: Result of expression 'triangleSpan.nextSibling.nextSibling.nextSibling.nextSibling' [null] is not an object.
+CONSOLE MESSAGE: line 40: TypeError: Result of expression 'triangleSpan.nextSibling.nextSibling.nextSibling.nextSibling' [null] is not an object.
layer at (0,0) size 800x600
RenderView at (0,0) size 800x600
layer at (0,0) size 800x600
-CONSOLE MESSAGE: line 14: Result of expression 'document.styleSheets[1]' [undefined] is not an object.
+CONSOLE MESSAGE: line 14: TypeError: Result of expression 'document.styleSheets[1]' [undefined] is not an object.
layer at (0,0) size 800x600
RenderView at (0,0) size 800x600
layer at (0,0) size 800x76
-CONSOLE MESSAGE: line 7: Can't find variable: appendCellAt
+CONSOLE MESSAGE: line 7: ReferenceError: Can't find variable: appendCellAt
layer at (0,0) size 800x600
RenderView at (0,0) size 800x600
layer at (0,0) size 800x600
-CONSOLE MESSAGE: line 7: Can't find variable: appendCellAt
+CONSOLE MESSAGE: line 7: ReferenceError: Can't find variable: appendCellAt
layer at (0,0) size 800x600
RenderView at (0,0) size 800x600
layer at (0,0) size 800x600
-CONSOLE MESSAGE: line 10: Can't find variable: appendCell
+CONSOLE MESSAGE: line 10: ReferenceError: Can't find variable: appendCell
layer at (0,0) size 800x600
RenderView at (0,0) size 800x600
layer at (0,0) size 800x600
-CONSOLE MESSAGE: line 10: Can't find variable: appendCell
+CONSOLE MESSAGE: line 10: ReferenceError: Can't find variable: appendCell
layer at (0,0) size 800x600
RenderView at (0,0) size 800x600
layer at (0,0) size 800x600
-CONSOLE MESSAGE: line 0: undefined
+CONSOLE MESSAGE: line 0: TransactionCallbackError
If WebKit doesn't crash, this test has passed
+2008-07-19 Oliver Hunt <oliver@apple.com>
+
+ Reviewed by Mark Rowe.
+
+ Bug 15979: Console logs in a database callback lose line number information
+ <https://bugs.webkit.org/show_bug.cgi?id=15979>
+
+ The problem was that there were multiple versions of the logic to
+ log an exception to the console, many of which were incorrect. We
+ resolve this by making one single shared reportException method,
+ which handles the exceptions correctly.
+
+ This improves fidelity of callback errors, and ensures that
+ exceptions thrown in timer callbacks correctly report line numbers,
+ etc.
+
+ Test: fast/js/exceptions-thrown-in-callbacks.html
+
+ * bindings/js/JSCustomSQLStatementCallback.cpp:
+ (WebCore::JSCustomSQLStatementCallback::handleEvent):
+ * bindings/js/JSCustomSQLStatementErrorCallback.cpp:
+ (WebCore::JSCustomSQLStatementErrorCallback::handleEvent):
+ * bindings/js/JSCustomSQLTransactionCallback.cpp:
+ (WebCore::JSCustomSQLTransactionCallback::handleEvent):
+ * bindings/js/JSCustomSQLTransactionErrorCallback.cpp:
+ (WebCore::JSCustomSQLTransactionErrorCallback::handleEvent):
+ * bindings/js/JSCustomVoidCallback.cpp:
+ (WebCore::JSCustomVoidCallback::handleEvent):
+ * bindings/js/JSCustomXPathNSResolver.cpp:
+ (WebCore::JSCustomXPathNSResolver::lookupNamespaceURI):
+ * bindings/js/JSEventListener.cpp:
+ (WebCore::JSAbstractEventListener::handleEvent):
+ * bindings/js/ScheduledAction.cpp:
+ (WebCore::ScheduledAction::execute):
+ * bindings/js/ScriptController.cpp:
+ (WebCore::ScriptController::evaluate):
+ * bindings/objc/WebScriptObject.mm:
+ (WebCore::addExceptionToConsole):
+ * page/Console.cpp:
+ (WebCore::Console::reportException):
+ * page/Console.h:
+
2008-07-20 Nikolas Zimmermann <zimmermann@kde.org>
Rubber stamped by Oliver.
* loader/TextResourceDecoder.cpp:
(WebCore::TextResourceDecoder::checkForHeadCharset):
-2008-07-19 Oliver Hunt <oliver@apple.com>
+2008-07-20 Oliver Hunt <oliver@apple.com>
- Reviewed by NOBODY (Build fix).
+ Reviewed by NOBODY (build fix).
Attempt to fix windows build
globalObject->stopTimeoutCheck();
if (exec->hadException()) {
- JSObject* exception = exec->exception()->toObject(exec);
- String message = exception->get(exec, exec->propertyNames().message)->toString(exec);
- int lineNumber = exception->get(exec, Identifier(exec, "line"))->toInt32(exec);
- String sourceURL = exception->get(exec, Identifier(exec, "sourceURL"))->toString(exec);
- m_frame->domWindow()->console()->addMessage(JSMessageSource, ErrorMessageLevel, message, lineNumber, sourceURL);
+ m_frame->domWindow()->console()->reportCurrentException(exec);
raisedException = true;
-
- exec->clearException();
}
Document::updateDocumentsRendering();
globalObject->stopTimeoutCheck();
if (exec->hadException()) {
- JSObject* exception = exec->exception()->toObject(exec);
- String message = exception->get(exec, exec->propertyNames().message)->toString(exec);
- int lineNumber = exception->get(exec, Identifier(exec, "line"))->toInt32(exec);
- String sourceURL = exception->get(exec, Identifier(exec, "sourceURL"))->toString(exec);
- m_frame->domWindow()->console()->addMessage(JSMessageSource, ErrorMessageLevel, message, lineNumber, sourceURL);
- exec->clearException();
+ m_frame->domWindow()->console()->reportCurrentException(exec);
// The spec says:
// "If the error callback returns false, then move on to the next statement..."
globalObject->stopTimeoutCheck();
if (exec->hadException()) {
- JSObject* exception = exec->exception()->toObject(exec);
- String message = exception->get(exec, exec->propertyNames().message)->toString(exec);
- int lineNumber = exception->get(exec, Identifier(exec, "line"))->toInt32(exec);
- String sourceURL = exception->get(exec, Identifier(exec, "sourceURL"))->toString(exec);
- m_data->frame()->domWindow()->console()->addMessage(JSMessageSource, ErrorMessageLevel, message, lineNumber, sourceURL);
- exec->clearException();
+ m_data->frame()->domWindow()->console()->reportCurrentException(exec);
raisedException = true;
}
result = call(exec, function, callType, callData, m_callback, args);
globalObject->stopTimeoutCheck();
- if (exec->hadException()) {
- JSObject* exception = exec->exception()->toObject(exec);
- String message = exception->get(exec, exec->propertyNames().message)->toString(exec);
- int lineNumber = exception->get(exec, Identifier(exec, "line"))->toInt32(exec);
- String sourceURL = exception->get(exec, Identifier(exec, "sourceURL"))->toString(exec);
- m_frame->domWindow()->console()->addMessage(JSMessageSource, ErrorMessageLevel, message, lineNumber, sourceURL);
- exec->clearException();
- }
+ if (exec->hadException())
+ m_frame->domWindow()->console()->reportCurrentException(exec);
Document::updateDocumentsRendering();
call(exec, function, callType, callData, m_callback, args);
globalObject->stopTimeoutCheck();
- if (exec->hadException()) {
- JSObject* exception = exec->exception()->toObject(exec);
- String message = exception->get(exec, exec->propertyNames().message)->toString(exec);
- int lineNumber = exception->get(exec, Identifier(exec, "line"))->toInt32(exec);
- String sourceURL = exception->get(exec, Identifier(exec, "sourceURL"))->toString(exec);
- m_frame->domWindow()->console()->addMessage(JSMessageSource, ErrorMessageLevel, message, lineNumber, sourceURL);
- exec->clearException();
- }
+ if (exec->hadException())
+ m_frame->domWindow()->console()->reportCurrentException(exec);
Document::updateDocumentsRendering();
}
globalObject->stopTimeoutCheck();
String result;
- if (exec->hadException()) {
- JSObject* exception = exec->exception()->toObject(exec);
- String message = exception->get(exec, exec->propertyNames().message)->toString(exec);
- int lineNumber = exception->get(exec, Identifier(exec, "line"))->toInt32(exec);
- String sourceURL = exception->get(exec, Identifier(exec, "sourceURL"))->toString(exec);
- m_frame->domWindow()->console()->addMessage(JSMessageSource, ErrorMessageLevel, message, lineNumber, sourceURL);
- exec->clearException();
- } else {
+ if (exec->hadException())
+ m_frame->domWindow()->console()->reportCurrentException(exec);
+ else {
if (!retval->isUndefinedOrNull())
result = retval->toString(exec);
}
window->setCurrentEvent(savedEvent);
- if (exec->hadException()) {
- JSObject* exception = exec->exception()->toObject(exec);
- String message = exception->get(exec, exec->propertyNames().message)->toString(exec);
- int lineNumber = exception->get(exec, Identifier(exec, "line"))->toInt32(exec);
- String sourceURL = exception->get(exec, Identifier(exec, "sourceURL"))->toString(exec);
- frame->domWindow()->console()->addMessage(JSMessageSource, ErrorMessageLevel, message, lineNumber, sourceURL);
- exec->clearException();
- } else {
+ if (exec->hadException())
+ frame->domWindow()->console()->reportCurrentException(exec);
+ else {
if (!retval->isUndefinedOrNull() && event->storesResultAsString())
event->storeResult(retval->toString(exec));
if (m_isHTML) {
window->startTimeoutCheck();
call(exec, m_function, callType, callData, windowShell, args);
window->stopTimeoutCheck();
- if (exec->hadException()) {
- JSObject* exception = exec->exception()->toObject(exec);
- exec->clearException();
- String message = exception->get(exec, exec->propertyNames().message)->toString(exec);
- int lineNumber = exception->get(exec, Identifier(exec, "line"))->toInt32(exec);
- frame->domWindow()->console()->addMessage(JSMessageSource, ErrorMessageLevel, message, lineNumber, String());
- }
+ if (exec->hadException())
+ frame->domWindow()->console()->reportCurrentException(exec);
}
} else
frame->loader()->executeScript(m_code);
return comp.value();
}
- if (comp.complType() == Throw) {
- UString errorMessage = comp.value()->toString(exec);
- int lineNumber = comp.value()->toObject(exec)->get(exec, Identifier(exec, "line"))->toInt32(exec);
- UString exceptionSourceURL = comp.value()->toObject(exec)->get(exec, Identifier(exec, "sourceURL"))->toString(exec);
- m_frame->domWindow()->console()->addMessage(JSMessageSource, ErrorMessageLevel, errorMessage, lineNumber, exceptionSourceURL);
- }
+ if (comp.complType() == Throw)
+ m_frame->domWindow()->console()->reportException(exec, comp.value());
m_sourceURL = savedSourceURL;
return 0;
static void addExceptionToConsole(ExecState* exec)
{
JSDOMWindow* window = asJSDOMWindow(exec->dynamicGlobalObject());
- JSObject* exception = exec->exception()->toObject(exec);
- if (!window || !exception)
+ if (!window || !exec->hadException())
return;
- String message = exception->get(exec, exec->propertyNames().message)->toString(exec);
- int lineNumber = exception->get(exec, Identifier(exec, "line"))->toInt32(exec);
- String sourceURL = exception->get(exec, Identifier(exec, "sourceURL"))->toString(exec);
- window->impl()->console()->addMessage(JSMessageSource, ErrorMessageLevel, message, lineNumber, sourceURL);
+ window->impl()->console()->reportCurrentException(exec);
}
} // namespace WebCore
printToStandardOut(WarningMessageLevel, exec, arguments, url);
}
+void Console::reportException(ExecState* exec, JSValue* exception)
+{
+ UString errorMessage = exception->toString(exec);
+ JSObject* exceptionObject = exception->toObject(exec);
+ int lineNumber = exceptionObject->get(exec, Identifier(exec, "line"))->toInt32(exec);
+ UString exceptionSourceURL = exceptionObject->get(exec, Identifier(exec, "sourceURL"))->toString(exec);
+ addMessage(JSMessageSource, ErrorMessageLevel, errorMessage, lineNumber, exceptionSourceURL);
+}
+
+void Console::reportCurrentException(ExecState* exec)
+{
+ JSValue* exception = exec->exception();
+ exec->clearException();
+ reportException(exec, exception);
+}
+
} // namespace WebCore
class ExecState;
class ArgList;
class Profile;
+ class JSValue;
}
namespace WebCore {
void finishedProfiling(PassRefPtr<KJS::Profile>);
+ void reportException(KJS::ExecState*, KJS::JSValue*);
+ void reportCurrentException(KJS::ExecState*);
private:
Console(Frame*);