Bug 1375447 - Save exception state in Debugger::onTrap. r=jandem
authorShu-yu Guo <shu@rfrn.org>
Wed, 28 Jun 2017 14:22:00 -0400
changeset 607780 5b77f711e2b4990067452d5dc04f613c42248b6d
parent 607779 734640228fbc00212f96ea1a362247887d739b73
child 607781 914e475abbf414b129bc322b843541c5e9b0b6ab
push id68110
push userbmo:nchen@mozilla.com
push dateWed, 12 Jul 2017 21:26:51 +0000
reviewersjandem
bugs1375447
milestone56.0a1
Bug 1375447 - Save exception state in Debugger::onTrap. r=jandem
js/src/jit-test/tests/debug/bug1375447.js
js/src/vm/Debugger.cpp
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/bug1375447.js
@@ -0,0 +1,18 @@
+var g = newGlobal();
+var dbg = new Debugger;
+var gw = dbg.addDebuggee(g);
+g.eval(`
+var line0 = Error().lineNumber;
+function f() {
+    try {
+  throw 4;
+    } catch(e) {}
+}
+`);
+var script = gw.getOwnPropertyDescriptor("f").value.script;
+var handler = {
+    hit: function() {}
+};
+var offs = script.getLineOffsets(g.line0 + 4);
+for (var i = 0; i < offs.length; i++) script.setBreakpoint(offs[i], handler);
+assertEq(g.f(), undefined);
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -1947,16 +1947,17 @@ Debugger::slowPathOnNewWasmInstance(JSCo
 
     MOZ_ASSERT(status == JSTRAP_CONTINUE);
 }
 
 /* static */ JSTrapStatus
 Debugger::onTrap(JSContext* cx, MutableHandleValue vp)
 {
     FrameIter iter(cx);
+    JS::AutoSaveExceptionState saveExc(cx);
     Rooted<GlobalObject*> global(cx);
     BreakpointSite* site;
     bool isJS; // true when iter.hasScript(), false when iter.isWasm()
     jsbytecode* pc; // valid when isJS == true
     uint32_t bytecodeOffset; // valid when isJS == false
     if (iter.hasScript()) {
         RootedScript script(cx, iter.script());
         MOZ_ASSERT(script->isDebuggee());
@@ -2044,23 +2045,17 @@ Debugger::onSingleStep(JSContext* cx, Mu
     FrameIter iter(cx);
 
     /*
      * We may be stepping over a JSOP_EXCEPTION, that pushes the context's
      * pending exception for a 'catch' clause to handle. Don't let the
      * onStep handlers mess with that (other than by returning a resumption
      * value).
      */
-    RootedValue exception(cx, UndefinedValue());
-    bool exceptionPending = cx->isExceptionPending();
-    if (exceptionPending) {
-        if (!cx->getPendingException(&exception))
-            return JSTRAP_ERROR;
-        cx->clearPendingException();
-    }
+    JS::AutoSaveExceptionState saveExc(cx);
 
     /*
      * Build list of Debugger.Frame instances referring to this frame with
      * onStep handlers.
      */
     Rooted<DebuggerFrameVector> frames(cx, DebuggerFrameVector(cx));
     if (!getDebuggerFrames(iter.abstractFramePtr(), &frames))
         return JSTRAP_ERROR;
@@ -2116,18 +2111,16 @@ Debugger::onSingleStep(JSContext* cx, Mu
         bool success = handler->onStep(cx, frame, status, vp);
         status = dbg->processParsedHandlerResult(ac, iter.abstractFramePtr(), iter.pc(), success,
                                                  status, vp);
         if (status != JSTRAP_CONTINUE)
             return status;
     }
 
     vp.setUndefined();
-    if (exceptionPending)
-        cx->setPendingException(exception);
     return JSTRAP_CONTINUE;
 }
 
 JSTrapStatus
 Debugger::fireNewGlobalObject(JSContext* cx, Handle<GlobalObject*> global, MutableHandleValue vp)
 {
     RootedObject hook(cx, getHook(OnNewGlobalObject));
     MOZ_ASSERT(hook);