diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 9eade5005d5c..d3db5fd67be1 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -454,14 +454,27 @@ ShellInterruptCallback(JSContext* cx) 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 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