Bug 1269711 - Disallow JS interrupt callback function to affect exception state of interrupted JS. (r=jimb)
authorShu-yu Guo <shu@rfrn.org>
Wed, 08 Jun 2016 21:01:00 -0700
changeset 301204 a945349f5f3d10c3ffa7a1714d71cf8e6773aa6e
parent 301203 75f65d79283ffe8fbfa797d62e64d7b797d20f6c
child 301205 e5937b04cdebdce11afcd65f5742f32ddc095a99
push id78250
push usershu@rfrn.org
push dateThu, 09 Jun 2016 04:00:04 +0000
treeherdermozilla-inbound@4b405b61dff5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjimb
bugs1269711
milestone50.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 1269711 - Disallow JS interrupt callback function to affect exception state of interrupted JS. (r=jimb)
js/src/shell/js.cpp
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -453,24 +453,37 @@ ShellInterruptCallback(JSContext* cx)
     // Reset serviceInterrupt. CancelExecution or InterruptIf will set it to
     // true to distinguish watchdog or user triggered interrupts.
     // Do this first to prevent other interrupts that may occur while the
     // user-supplied callback is executing from re-entering the handler.
     sr->serviceInterrupt = false;
 
     bool result;
     if (sr->haveInterruptFunc) {
+        bool wasAlreadyThrowing = cx->isExceptionPending();
         JS::AutoSaveExceptionState savedExc(cx);
         JSAutoCompartment ac(cx, &sr->interruptFunc.toObject());
         RootedValue rval(cx);
-        if (!JS_CallFunctionValue(cx, nullptr, sr->interruptFunc,
-                                  JS::HandleValueArray::empty(), &rval))
+
+        // Report any exceptions thrown by the JS interrupt callback, but do
+        // *not* keep it on the cx. The interrupt handler is invoked at points
+        // that are not expected to throw catchable exceptions, like at
+        // JSOP_RETRVAL.
+        //
+        // If the interrupted JS code was already throwing, any exceptions
+        // thrown by the interrupt handler are silently swallowed.
         {
-            return false;
+            Maybe<AutoReportException> are;
+            if (!wasAlreadyThrowing)
+                are.emplace(cx);
+            result = JS_CallFunctionValue(cx, nullptr, sr->interruptFunc,
+                                          JS::HandleValueArray::empty(), &rval);
         }
+        savedExc.restore();
+
         if (rval.isBoolean())
             result = rval.toBoolean();
         else
             result = false;
     } else {
         result = false;
     }