Bug 755515: Catch exceptions in error handlers. r=sicking
authorKyle Huey <khuey@kylehuey.com>
Fri, 29 Jun 2012 09:48:34 -0700
changeset 102717 f22f90356a87788c90e011c6bd0ca72368a52a4a
parent 102716 9c6ad99de47a6037c61c17aae044c41b4b8a8197
child 102718 4290c4653e8c509e7ced6bb86f33c26d5362259d
push id1316
push userakeybl@mozilla.com
push dateMon, 27 Aug 2012 22:37:00 +0000
treeherdermozilla-beta@db4b09302ee2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssicking
bugs755515
milestone16.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 755515: Catch exceptions in error handlers. r=sicking
dom/indexedDB/AsyncConnectionHelper.cpp
dom/indexedDB/test/Makefile.in
dom/indexedDB/test/exceptions_in_events_iframe.html
dom/indexedDB/test/exceptions_in_success_events_iframe.html
dom/indexedDB/test/test_exceptions_in_events.html
dom/indexedDB/test/test_exceptions_in_success_events.html
--- a/dom/indexedDB/AsyncConnectionHelper.cpp
+++ b/dom/indexedDB/AsyncConnectionHelper.cpp
@@ -463,16 +463,26 @@ AsyncConnectionHelper::OnError()
   bool doDefault;
   nsresult rv = mRequest->DispatchEvent(event, &doDefault);
   if (NS_SUCCEEDED(rv)) {
     NS_ASSERTION(!mTransaction ||
                  mTransaction->IsOpen() ||
                  mTransaction->IsAborted(),
                  "How else can this be closed?!");
 
+    nsEvent* internalEvent = event->GetInternalNSEvent();
+    NS_ASSERTION(internalEvent, "This should never be null!");
+
+    if ((internalEvent->flags & NS_EVENT_FLAG_EXCEPTION_THROWN) &&
+        mTransaction &&
+        mTransaction->IsOpen() &&
+        NS_FAILED(mTransaction->Abort())) {
+      NS_WARNING("Failed to abort transaction!");
+    }
+
     if (doDefault &&
         mTransaction &&
         mTransaction->IsOpen() &&
         NS_FAILED(mTransaction->Abort(mRequest))) {
       NS_WARNING("Failed to abort transaction!");
     }
   }
   else {
--- a/dom/indexedDB/test/Makefile.in
+++ b/dom/indexedDB/test/Makefile.in
@@ -15,17 +15,17 @@ XPCSHELL_TESTS = unit
 
 include $(topsrcdir)/config/rules.mk
 
 TEST_FILES = \
   bfcache_iframe1.html \
   bfcache_iframe2.html \
   error_events_abort_transactions_iframe.html \
   event_propagation_iframe.html \
-  exceptions_in_success_events_iframe.html \
+  exceptions_in_events_iframe.html \
   file.js \
   helpers.js \
   leaving_page_iframe.html \
   test_add_put.html \
   test_add_twice_failure.html \
   test_advance.html \
   test_autoIncrement_indexes.html \
   test_autoIncrement.html \
@@ -39,17 +39,17 @@ TEST_FILES = \
   test_cursors.html \
   test_cursor_mutation.html \
   test_cursor_update_updates_indexes.html \
   test_deleteDatabase.html \
   test_deleteDatabase_interactions.html \
   test_error_events_abort_transactions.html \
   test_event_propagation.html \
   test_event_source.html \
-  test_exceptions_in_success_events.html \
+  test_exceptions_in_events.html \
   test_file_array.html \
   test_file_cross_database_copying.html \
   test_file_delete.html \
   test_file_os_delete.html \
   test_file_put_get_object.html \
   test_file_put_get_values.html \
   test_file_replace.html \
   test_file_resurrection_delete.html \
new file mode 100644
--- /dev/null
+++ b/dom/indexedDB/test/exceptions_in_events_iframe.html
@@ -0,0 +1,182 @@
+<!--
+  Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+<head>
+  <title>Indexed Database Property Test</title>
+
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+
+  <script type="text/javascript;version=1.7">
+    let testGenerator = testSteps();
+
+    function ok(val, message) {
+      val = val ? "true" : "false";
+      window.parent.postMessage("SimpleTest.ok(" + val + ", '" + message +
+                                "');", "*");
+    }
+
+    function is(a, b, message) {
+      ok(a == b, message);
+    }
+
+    function grabEventAndContinueHandler(event) {
+      testGenerator.send(event);
+    }
+
+    function errorHandler(event) {
+      ok(false, "indexedDB error, code " + event.target.errorCode);
+      finishTest();
+    }
+
+    function unexpectedSuccessHandler(event) {
+      ok(false, "got success when it was not expected!");
+      finishTest();
+    }
+
+    function finishTest() {
+      // Let window.onerror have a chance to fire
+      setTimeout(function() {
+        setTimeout(function() {
+          testGenerator.close();
+          window.parent.postMessage("SimpleTest.finish();", "*");
+        }, 0);
+      }, 0);
+    }
+
+    window.onerror = function() {
+      return false;
+    };
+
+    function testSteps() {
+      window.parent.SpecialPowers.addPermission("indexedDB", true, document);
+
+      // Test 1: Throwing an exception in an upgradeneeded handler should
+      // abort the versionchange transaction and fire an error at the request.
+      let request = mozIndexedDB.open(window.location.pathname, 1);
+      request.onerror = errorHandler;
+      request.onsuccess = unexpectedSuccessHandler;
+      request.onupgradeneeded = function () {
+        let transaction = request.transaction;
+        transaction.oncomplete = unexpectedSuccessHandler;
+        transaction.onabort = grabEventAndContinueHandler
+        throw "STOP";
+      };
+
+      let event = yield;
+      is(event.type, "abort",
+         "Throwing during an upgradeneeded event should abort the transaction.");
+      is(event.target.error, null, "Got null error object");
+
+      request.onerror = grabEventAndContinueHandler;
+      event = yield;
+
+      is(event.type, "error",
+         "Throwing during an upgradeneeded event should fire an error.");
+
+      // Test 2: Throwing during a request's success handler should abort the
+      // transaction.
+      let request = mozIndexedDB.open(window.location.pathname, 1);
+      request.onerror = errorHandler;
+      request.onblocked = errorHandler;
+      request.onupgradeneeded = grabEventAndContinueHandler;
+      request.onsuccess = unexpectedSuccessHandler;
+      let openrequest = request;
+      let event = yield;
+
+      request.onupgradeneeded = unexpectedSuccessHandler;
+
+      let db = event.target.result;
+      db.onerror = function(event) {
+        event.preventDefault();
+      };
+
+      event.target.transaction.oncomplete = unexpectedSuccessHandler;
+      event.target.transaction.onabort = grabEventAndContinueHandler;
+
+      is(db.version, 1, "Correct version");
+      is(db.objectStoreNames.length, 0, "Correct objectStoreNames length");
+
+      let objectStore = db.createObjectStore("foo");
+
+      is(db.objectStoreNames.length, 1, "Correct objectStoreNames length");
+      ok(db.objectStoreNames.contains("foo"), "Has correct objectStore");
+
+      request = objectStore.add({}, 1);
+      request.onsuccess = function(event) {
+        throw "foo";
+      };
+
+      event = yield;
+
+      is(event.type, "abort", "Got transaction abort event");
+      is(event.target.error, null, "Got null error object");
+      openrequest.onerror = grabEventAndContinueHandler;
+
+      event = yield;
+
+      is(event.type, "error", "Got IDBOpenDBRequest error event");
+      is(event.target, openrequest, "Right event target");
+      is(event.target.error.name, "AbortError", "Right error name");
+
+      // Test 3: Throwing during a request's error handler should abort the
+      // transaction, even if preventDefault is called on the error event.
+      let request = mozIndexedDB.open(window.location.pathname, 1);
+      request.onerror = errorHandler;
+      request.onblocked = errorHandler;
+      request.onupgradeneeded = grabEventAndContinueHandler;
+      request.onsuccess = unexpectedSuccessHandler;
+      let openrequest = request;
+      let event = yield;
+
+      request.onupgradeneeded = unexpectedSuccessHandler;
+
+      let db = event.target.result;
+      db.onerror = function(event) {
+        event.preventDefault();
+      };
+
+      event.target.transaction.oncomplete = unexpectedSuccessHandler;
+      event.target.transaction.onabort = grabEventAndContinueHandler;
+
+      is(db.version, 1, "Correct version");
+      is(db.objectStoreNames.length, 0, "Correct objectStoreNames length");
+
+      let objectStore = db.createObjectStore("foo");
+
+      is(db.objectStoreNames.length, 1, "Correct objectStoreNames length");
+      ok(db.objectStoreNames.contains("foo"), "Has correct objectStore");
+
+      request = objectStore.add({}, 1);
+      request.onerror = errorHandler;
+      request = objectStore.add({}, 1);
+      request.onsuccess = unexpectedSuccessHandler;
+      request.onerror = function (event) {
+        event.preventDefault();
+        throw "STOP";
+      };
+
+      event = yield;
+
+      is(event.type, "abort", "Got transaction abort event");
+      is(event.target.error, null, "Got null error object");
+      openrequest.onerror = grabEventAndContinueHandler;
+
+      event = yield;
+
+      is(event.type, "error", "Got IDBOpenDBRequest error event");
+      is(event.target, openrequest, "Right event target");
+      is(event.target.error.name, "AbortError", "Right error name");
+
+      finishTest();
+      yield;
+    }
+  </script>
+
+</head>
+
+<body onload="testGenerator.next();"></body>
+
+</html>
deleted file mode 100644
--- a/dom/indexedDB/test/exceptions_in_success_events_iframe.html
+++ /dev/null
@@ -1,116 +0,0 @@
-<!--
-  Any copyright is dedicated to the Public Domain.
-  http://creativecommons.org/publicdomain/zero/1.0/
--->
-<html>
-<head>
-  <title>Indexed Database Property Test</title>
-
-  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
-
-  <script type="text/javascript;version=1.7">
-    let testGenerator = testSteps();
-
-    function ok(val, message) {
-      val = val ? "true" : "false";
-      window.parent.postMessage("SimpleTest.ok(" + val + ", '" + message +
-                                "');", "*");
-    }
-
-    function is(a, b, message) {
-      ok(a == b, message);
-    }
-
-    function grabEventAndContinueHandler(event) {
-      testGenerator.send(event);
-    }
-
-    function errorHandler(event) {
-      ok(false, "indexedDB error, code " + event.target.errorCode);
-      finishTest();
-    }
-
-    function unexpectedSuccessHandler(event) {
-      ok(false, "got success when it was not expected!");
-      finishTest();
-    }
-
-    function finishTest() {
-      // Let window.onerror have a chance to fire
-      setTimeout(function() {
-        setTimeout(function() {
-          testGenerator.close();
-          window.parent.postMessage("SimpleTest.finish();", "*");
-        }, 0);
-      }, 0);
-    }
-
-    window.onerror = function() {
-      return false;
-    };
-
-    function testSteps() {
-      window.parent.SpecialPowers.addPermission("indexedDB", true, document);
-
-      let request = mozIndexedDB.open(window.location.pathname, 1);
-      request.onerror = grabEventAndContinueHandler;
-      request.onsuccess = errorHandler;
-      request.onupgradeneeded = function () {
-        throw "STOP";
-      };
-
-      let event = yield;
-
-      is(event.type, "error",
-         "Throwing during an upgradeneeded event should fire an error.");
-
-      let request = mozIndexedDB.open(window.location.pathname, 1);
-      request.onerror = grabEventAndContinueHandler;
-      request.onblocked = errorHandler;
-      request.onupgradeneeded = grabEventAndContinueHandler;
-      let openrequest = request;
-      let event = yield;
-
-      let db = event.target.result;
-      db.onerror = function(event) {
-        event.preventDefault();
-      };
-
-      event.target.transaction.oncomplete = unexpectedSuccessHandler;
-      event.target.transaction.onabort = grabEventAndContinueHandler;
-
-      is(db.version, 1, "Correct version");
-      is(db.objectStoreNames.length, 0, "Correct objectStoreNames length");
-
-      let objectStore = db.createObjectStore("foo");
-
-      is(db.objectStoreNames.length, 1, "Correct objectStoreNames length");
-      ok(db.objectStoreNames.contains("foo"), "Has correct objectStore");
-
-      request = objectStore.add({}, 1);
-      request.onsuccess = function(event) {
-        throw "foo";
-      };
-
-      event = yield;
-
-      is(event.type, "abort", "Got transaction abort event");
-      is(event.target.error, null, "Got null error object");
-
-      event = yield;
-
-      is(event.type, "error", "Got IDBOpenDBRequest error event");
-      is(event.target, openrequest, "Right event target");
-      is(event.target.error.name, "AbortError", "Right error name");
-
-      finishTest();
-      yield;
-    }
-  </script>
-
-</head>
-
-<body onload="testGenerator.next();"></body>
-
-</html>
new file mode 100644
--- /dev/null
+++ b/dom/indexedDB/test/test_exceptions_in_events.html
@@ -0,0 +1,30 @@
+<!--
+  Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+<head>
+  <title>Indexed Database Property Test</title>
+
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+
+  <script type="text/javascript;version=1.7">
+    function runTest() {
+      SimpleTest.waitForExplicitFinish();
+
+      function messageListener(event) {
+        eval(event.data);
+      }
+
+      window.addEventListener("message", messageListener, false);
+    }
+  </script>
+
+</head>
+
+<body onload="runTest();">
+  <iframe src="exceptions_in_events_iframe.html"></iframe>
+</body>
+
+</html>
deleted file mode 100644
--- a/dom/indexedDB/test/test_exceptions_in_success_events.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!--
-  Any copyright is dedicated to the Public Domain.
-  http://creativecommons.org/publicdomain/zero/1.0/
--->
-<html>
-<head>
-  <title>Indexed Database Property Test</title>
-
-  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
-
-  <script type="text/javascript;version=1.7">
-    function runTest() {
-      SimpleTest.waitForExplicitFinish();
-
-      function messageListener(event) {
-        eval(event.data);
-      }
-
-      window.addEventListener("message", messageListener, false);
-    }
-  </script>
-
-</head>
-
-<body onload="runTest();">
-  <iframe src="exceptions_in_success_events_iframe.html"></iframe>
-</body>
-
-</html>