Bug 906963 - Detect whether a bytecode offset is within the scope of a catch statement.

This commit is contained in:
Eddy Bruel 2013-08-30 10:52:31 +02:00
parent f587d1f5aa
commit 5ca960bd08
2 changed files with 98 additions and 0 deletions

View File

@ -0,0 +1,64 @@
// Test if isInCatchScope properly detects catch blocks.
let g = newGlobal('new-compartment');
let dbg = new Debugger(g);
function test(string, mustBeCaught) {
let index = 0;
dbg.onExceptionUnwind = function (frame) {
let willBeCaught = false;
do {
if (frame.script.isInCatchScope(frame.offset)) {
willBeCaught = true;
break;
}
frame = frame.older;
} while (frame != null);
assertEq(willBeCaught, mustBeCaught[index++]);
};
try {
g.eval(string);
} catch (ex) {}
assertEq(index, mustBeCaught.length);
}
// Should correctly detect catch blocks
test("throw new Error();", [false]);
test("try { throw new Error(); } catch (e) {}", [true]);
test("try { throw new Error(); } finally {}", [false, false]);
test("try { throw new Error(); } catch (e) {} finally {}", [true]);
// Source of the exception shouldn't matter
test("(null)();", [false]);
test("try { (null)(); } catch (e) {}", [true]);
test("try { (null)(); } finally {}", [false, false]);
test("try { (null)(); } catch (e) {} finally {}", [true]);
// Should correctly detect catch blocks in functions
test("function f() { throw new Error(); } f();", [false, false]);
test("function f() { try { throw new Error(); } catch (e) {} } f();", [true]);
test("function f() { try { throw new Error(); } finally {} } f();", [false, false, false]);
test("function f() { try { throw new Error(); } catch (e) {} finally {} } f();", [true]);
// Should correctly detect catch blocks in evals
test("eval('throw new Error();')", [false, false]);
test("eval('try { throw new Error(); } catch (e) {}');", [true]);
test("eval('try { throw new Error(); } finally {}');", [false, false, false]);
test("eval('try { throw new Error(); } catch (e) {} finally {}');", [true]);
// Should correctly detect rethrows
test("try { throw new Error(); } catch (e) { throw e; }", [true, false]);
test("try { try { throw new Error(); } catch (e) { throw e; } } catch (e) {}", [true, true]);
test("try { try { throw new Error(); } finally {} } catch (e) {}", [true, true]);
test("function f() { try { throw new Error(); } catch (e) { throw e; } } f();", [true, false, false]);
test("function f() { try { try { throw new Error(); } catch (e) { throw e; } } catch (e) {} } f();", [true, true]);
test("function f() { try { try { throw new Error(); } finally {} } catch (e) {} } f();", [true, true]);
test("eval('try { throw new Error(); } catch (e) { throw e; }')", [true, false, false]);
test("eval('try { try { throw new Error(); } catch (e) { throw e; } } catch (e) {}')", [true, true]);
// Should correctly detect catch blocks across frame boundaries
test("function f() { throw new Error(); } try { f(); } catch (e) {}", [true, true]);
test("function f() { throw new Error(); } try { f(); } catch (e) { throw e; }", [true, true, false]);
test("try { eval('throw new Error()'); } catch (e) {}", [true, true]);
test("try { eval('throw new Error()'); } catch (e) { throw e; }", [true, true, false]);

View File

@ -3517,6 +3517,39 @@ DebuggerScript_clearAllBreakpoints(JSContext *cx, unsigned argc, Value *vp)
return true;
}
static bool
DebuggerScript_isInCatchScope(JSContext *cx, unsigned argc, Value* vp)
{
REQUIRE_ARGC("Debugger.Script.isInCatchScope", 1);
THIS_DEBUGSCRIPT_SCRIPT(cx, argc, vp, "isInCatchScope", args, obj, script);
size_t offset;
if (!ScriptOffset(cx, script, args[0], &offset))
return false;
/*
* Try note ranges are relative to the mainOffset of the script, so adjust
* offset accordingly.
*/
offset -= script->mainOffset;
args.rval().setBoolean(false);
if (script->hasTrynotes()) {
JSTryNote* tnBegin = script->trynotes()->vector;
JSTryNote* tnEnd = tnBegin + script->trynotes()->length;
while (tnBegin != tnEnd) {
if (offset - tnBegin->start < tnBegin->length &&
tnBegin->kind == JSTRY_CATCH)
{
args.rval().setBoolean(true);
break;
}
++tnBegin;
}
}
return true;
}
static bool
DebuggerScript_construct(JSContext *cx, unsigned argc, Value *vp)
{
@ -3546,6 +3579,7 @@ static const JSFunctionSpec DebuggerScript_methods[] = {
JS_FN("getBreakpoints", DebuggerScript_getBreakpoints, 1, 0),
JS_FN("clearBreakpoint", DebuggerScript_clearBreakpoint, 1, 0),
JS_FN("clearAllBreakpoints", DebuggerScript_clearAllBreakpoints, 0, 0),
JS_FN("isInCatchScope", DebuggerScript_isInCatchScope, 1, 0),
JS_FS_END
};