Change Debug.prototype.uncaughtExceptionHook to require a function or null, and pass the Debug object to uncaughtExceptionHook as the this-value.
authorJason Orendorff <jorendorff@mozilla.com>
Wed, 20 Apr 2011 14:45:14 -0500
changeset 74389 e3fa5d15ace6022fa0da0ae2756e737895c370ba
parent 74388 7818def1b65b4a23fcb496ce6354fbd9cbc6cc95
child 74390 3a24a9c046e5f6af5d28e2f3074aa4264151e6ab
push id2
push userbsmedberg@mozilla.com
push dateFri, 19 Aug 2011 14:38:13 +0000
milestone6.0a1
Change Debug.prototype.uncaughtExceptionHook to require a function or null, and pass the Debug object to uncaughtExceptionHook as the this-value.
js/src/js.msg
js/src/jsdbg.cpp
js/src/tests/js1_8_5/extensions/debug-object-18.js
js/src/tests/js1_8_5/extensions/debug-object-21.js
js/src/tests/js1_8_5/extensions/jstests.list
--- a/js/src/js.msg
+++ b/js/src/js.msg
@@ -346,8 +346,9 @@ MSG_DEF(JSMSG_CANT_WRAP_XML_OBJECT,   26
 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_NON_NATIVE_SCOPE,       266, 0, JSEXN_TYPEERR, "non-native scope object")
 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")
 MSG_DEF(JSMSG_CCW_REQUIRED,           270, 1, JSEXN_TYPEERR, "{0}: argument must be an object from a different compartment")
 MSG_DEF(JSMSG_DEBUG_BAD_RESUMPTION,   271, 0, JSEXN_TYPEERR, "debugger resumption value must be undefined, {throw: val}, {return: val}, or null")
+MSG_DEF(JSMSG_ASSIGN_FUNCTION_OR_NULL, 272, 1, JSEXN_TYPEERR, "value assigned to {0} must be a function or null")
--- a/js/src/jsdbg.cpp
+++ b/js/src/jsdbg.cpp
@@ -124,17 +124,17 @@ Debug::handleUncaughtException(AutoCompa
 {
     JSContext *cx = ac.context;
     if (cx->isExceptionPending()) {
         if (callHook && uncaughtExceptionHook) {
             Value fval = ObjectValue(*uncaughtExceptionHook);
             Value exc = cx->getPendingException();
             Value rv;
             cx->clearPendingException();
-            if (ExternalInvoke(cx, UndefinedValue(), fval, 1, &exc, &rv))
+            if (ExternalInvoke(cx, ObjectValue(*object), fval, 1, &exc, &rv))
                 return parseResumptionValue(ac, true, rv, vp, false);
         }
  
         if (cx->isExceptionPending()) {
             JS_ReportPendingException(cx);
             cx->clearPendingException();
         }
     }
@@ -389,18 +389,22 @@ Debug::getUncaughtExceptionHook(JSContex
     return true;
 }
 
 JSBool
 Debug::setUncaughtExceptionHook(JSContext *cx, uintN argc, Value *vp)
 {
     REQUIRE_ARGC("Debug.set uncaughtExceptionHook", 1);
     THISOBJ(cx, vp, Debug, "set uncaughtExceptionHook", thisobj, dbg);
-    if (!vp[2].isObjectOrNull())
-        return ReportObjectRequired(cx);
+    if (!vp[2].isNull() && (!vp[2].isObject() || !vp[2].toObject().isCallable())) {
+        JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_ASSIGN_FUNCTION_OR_NULL,
+                             "uncaughtExceptionHook");
+        return false;
+    }
+
     dbg->uncaughtExceptionHook = vp[2].toObjectOrNull();
     vp->setUndefined();
     return true;
 }
 
 JSBool
 Debug::construct(JSContext *cx, uintN argc, Value *vp)
 {
--- a/js/src/tests/js1_8_5/extensions/debug-object-18.js
+++ b/js/src/tests/js1_8_5/extensions/debug-object-18.js
@@ -9,16 +9,17 @@ var dbg = new Debug(g);
 var log;
 dbg.hooks = {
     debuggerHandler: function () {
         log += 'x';
         throw new TypeError("fail");
     }
 };
 dbg.uncaughtExceptionHook = function (exc) {
+    assertEq(this, dbg);
     assertEq(exc instanceof TypeError, true);
     log += '!';
 };
 
 log = '';
 g.eval("debugger");
 assertEq(log, 'x!');
 
new file mode 100644
--- /dev/null
+++ b/js/src/tests/js1_8_5/extensions/debug-object-21.js
@@ -0,0 +1,22 @@
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/licenses/publicdomain/
+
+// dumb basics of uncaughtExceptionHook
+
+var desc = Object.getOwnPropertyDescriptor(Debug.prototype, "uncaughtExceptionHook");
+assertEq(typeof desc.get, 'function');
+assertEq(typeof desc.set, 'function');
+
+assertThrows(function () { Debug.prototype.uncaughtExceptionHook = null; }, TypeError);
+
+var g = newGlobal('new-compartment');
+var dbg = new Debug(g);
+assertEq(desc.get.call(dbg), null);
+assertThrows(function () { dbg.uncaughtExceptionHook = []; }, TypeError);
+assertThrows(function () { dbg.uncaughtExceptionHook = 3; }, TypeError);
+dbg.uncaughtExceptionHook = Math.sin;
+assertEq(dbg.uncaughtExceptionHook, Math.sin);
+dbg.uncaughtExceptionHook = null;
+assertEq(dbg.uncaughtExceptionHook, null);
+
+reportCompare(0, 0, 'ok');
--- a/js/src/tests/js1_8_5/extensions/jstests.list
+++ b/js/src/tests/js1_8_5/extensions/jstests.list
@@ -56,8 +56,9 @@ skip-if(!xulRuntime.shell) script debug-
 skip-if(!xulRuntime.shell) script debug-object-13.js
 skip-if(!xulRuntime.shell) script debug-object-14.js
 skip-if(!xulRuntime.shell) script debug-object-15.js
 skip-if(!xulRuntime.shell) script debug-object-16.js
 skip-if(!xulRuntime.shell) script debug-object-17.js
 skip-if(!xulRuntime.shell) script debug-object-18.js
 skip-if(!xulRuntime.shell) script debug-object-19.js
 skip-if(!xulRuntime.shell) script debug-object-20.js
+skip-if(!xulRuntime.shell) script debug-object-21.js