Bug 890576 - Disallow resumption values in onNewGlobalObject hooks. r=jimb

This commit is contained in:
Bobby Holley 2013-08-01 18:38:44 -07:00
parent 7e75c28488
commit 1bf232fd00
4 changed files with 41 additions and 11 deletions

View File

@ -1,4 +1,4 @@
// Resumption values from onNewGlobalObject handlers are respected.
// Resumption values from onNewGlobalObject handlers are disallowed.
load(libdir + 'asserts.js');
@ -10,18 +10,25 @@ log = '';
assertEq(typeof newGlobal(), "object");
assertEq(log, 'n');
// For onNewGlobalObject, { return: V } resumption values are treated like
// 'undefined': the new global is still returned.
dbg.uncaughtExceptionHook = function (ex) { assertEq(/disallowed/.test(ex), true); log += 'u'; }
dbg.onNewGlobalObject = function (g) { log += 'n'; return { return: "snoo" }; };
log = '';
assertEq(typeof newGlobal(), "object");
assertEq(log, 'n');
assertEq(log, 'nu');
dbg.onNewGlobalObject = function (g) { log += 'n'; return { throw: "snoo" }; };
log = '';
assertThrowsValue(function () { newGlobal(); }, "snoo");
assertEq(log, 'n');
assertEq(typeof newGlobal(), "object");
assertEq(log, 'nu');
dbg.onNewGlobalObject = function (g) { log += 'n'; return null; };
log = '';
assertEq(evaluate('newGlobal();', { catchTermination: true }), "terminated");
assertEq(typeof newGlobal(), "object");
assertEq(log, 'nu');
dbg.uncaughtExceptionHook = function (ex) { assertEq(/foopy/.test(ex), true); log += 'u'; }
dbg.onNewGlobalObject = function (g) { log += 'n'; throw "foopy"; };
log = '';
assertEq(typeof newGlobal(), "object");
assertEq(log, 'nu');

View File

@ -16,8 +16,12 @@ dbg1.onNewGlobalObject = dbg2.onNewGlobalObject = dbg3.onNewGlobalObject = funct
return { throw: "snoo" };
return undefined;
};
dbg2.uncaughtExceptionHook = function (exn) {
assertEq(/disallowed/.test(exn), true);
log += 'u';
};
log = '';
count = 0;
assertThrowsValue(function () { newGlobal(); }, "snoo");
assertEq(log, '12');
assertEq(typeof newGlobal(), "object");
assertEq(log, '12u3');

View File

@ -316,7 +316,7 @@ MSG_DEF(JSMSG_SC_RECURSION, 262, 0, JSEXN_INTERNALERR, "recursive obje
MSG_DEF(JSMSG_UNUSED263, 263, 0, JSEXN_NONE, "")
MSG_DEF(JSMSG_BAD_CLONE_VERSION, 264, 0, JSEXN_ERR, "unsupported structured clone version")
MSG_DEF(JSMSG_CANT_CLONE_OBJECT, 265, 0, JSEXN_TYPEERR, "can't clone object")
MSG_DEF(JSMSG_UNUSED266, 266, 0, JSEXN_NONE, "")
MSG_DEF(JSMSG_DEBUG_RESUMPTION_VALUE_DISALLOWED, 266, 0, JSEXN_TYPEERR, "resumption values are disallowed in this hook")
MSG_DEF(JSMSG_STRICT_FUNCTION_STATEMENT, 267, 0, JSEXN_SYNTAXERR, "in strict mode code, functions may be declared only at top level or immediately within another function")
MSG_DEF(JSMSG_INVALID_FOR_IN_INIT, 268, 0, JSEXN_SYNTAXERR, "for-in loop let declaration may not have an initializer")
MSG_DEF(JSMSG_CLEARED_SCOPE, 269, 0, JSEXN_TYPEERR, "attempt to run compile-and-go script on a cleared scope")

View File

@ -1312,8 +1312,27 @@ Debugger::fireNewGlobalObject(JSContext *cx, Handle<GlobalObject *> global, Muta
return handleUncaughtException(ac, false);
RootedValue rv(cx);
// onNewGlobalObject is infallible, and thus is only allowed to return
// undefined as a resumption value. If it returns anything else, we throw.
// And if that happens, or if the hook itself throws, we invoke the
// uncaughtExceptionHook so that we never leave an exception pending on the
// cx. This allows JS_NewGlobalObject to avoid handling failures from debugger
// hooks.
bool ok = Invoke(cx, ObjectValue(*object), ObjectValue(*hook), 1, argv, &rv);
return parseResumptionValue(ac, ok, rv, vp);
if (ok && !rv.isUndefined()) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
JSMSG_DEBUG_RESUMPTION_VALUE_DISALLOWED);
ok = false;
}
// NB: Even though we don't care about what goes into it, we have to pass vp
// to handleUncaughtException so that it parses resumption values from the
// uncaughtExceptionHook and tells the caller whether we should execute the
// rest of the onNewGlobalObject hooks or not.
JSTrapStatus status = ok ? JSTRAP_CONTINUE
: handleUncaughtException(ac, vp, true);
JS_ASSERT(!cx->isExceptionPending());
return status;
}
bool