Bug 795119: Complain coherently when evalInGlobal{,withBindings} is passed a CCW to a global, not a global. r=luke
authorJim Blandy <jimb@mozilla.com>
Sat, 13 Oct 2012 16:04:16 -0700
changeset 110334 f67e5b827cdf0817f8721cbdc05c14210f6d2e21
parent 110333 147285c880287c930ba2d1afb197d0da7837b4d7
child 110335 567352805e77069675ac063ae2ff38ad2e3a9499
push id93
push usernmatsakis@mozilla.com
push dateWed, 31 Oct 2012 21:26:57 +0000
reviewersluke
bugs795119
milestone19.0a1
Bug 795119: Complain coherently when evalInGlobal{,withBindings} is passed a CCW to a global, not a global. r=luke
js/src/jit-test/tests/debug/Object-evalInGlobal-05.js
js/src/js.msg
js/src/vm/Debugger.cpp
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Object-evalInGlobal-05.js
@@ -0,0 +1,22 @@
+// Debugger.Object.prototype.evalInGlobal throws when asked to evaluate in a CCW of a global.
+
+load(libdir + 'asserts.js');
+
+var dbg = new Debugger();
+
+var g1 = newGlobal();
+var dg1 = dbg.addDebuggee(g1);
+
+var g2 = newGlobal();
+var dg2 = dbg.addDebuggee(g2);
+
+// Generate a Debugger.Object viewing g2 from g1's compartment.
+var dg1wg2 = dg1.makeDebuggeeValue(g2);
+assertEq(dg1wg2.global, dg1);
+assertEq(dg1wg2.unwrap(), dg2);
+assertThrowsInstanceOf(function () { dg1wg2.evalInGlobal('1'); }, TypeError);
+assertThrowsInstanceOf(function () { dg1wg2.evalInGlobalWithBindings('x', { x: 1 }); }, TypeError);
+
+// These, however, should not throw.
+assertEq(dg1wg2.unwrap().evalInGlobal('1729').return, 1729);
+assertEq(dg1wg2.unwrap().evalInGlobalWithBindings('x', { x: 1729 }).return, 1729);
--- a/js/src/js.msg
+++ b/js/src/js.msg
@@ -370,8 +370,9 @@ MSG_DEF(JSMSG_CANT_DEFINE_INVALID,    31
 MSG_DEF(JSMSG_CANT_DEFINE_NE_AS_NC,   317, 0, JSEXN_TYPEERR, "proxy can't define a non-existent property as non-configurable")
 MSG_DEF(JSMSG_INVALID_TRAP_RESULT,    318, 2, JSEXN_TYPEERR, "trap {1} for {0} returned an invalid result")
 MSG_DEF(JSMSG_CANT_SKIP_NC,           319, 0, JSEXN_TYPEERR, "proxy can't skip a non-configurable property")
 MSG_DEF(JSMSG_MUST_REPORT_SAME_VALUE, 320, 0, JSEXN_TYPEERR, "proxy must report the same value for a non-writable, non-configurable property")
 MSG_DEF(JSMSG_MUST_REPORT_UNDEFINED,  321, 0, JSEXN_TYPEERR, "proxy must report undefined for a non-configurable accessor property without a getter")
 MSG_DEF(JSMSG_CANT_SET_NW_NC,         322, 0, JSEXN_TYPEERR, "proxy can't successfully set a non-writable, non-configurable property")
 MSG_DEF(JSMSG_CANT_SET_WO_SETTER,     323, 0, JSEXN_TYPEERR, "proxy can't succesfully set an accessor property without a setter")
 MSG_DEF(JSMSG_DEBUG_BAD_REFERENT,     324, 2, JSEXN_TYPEERR, "{0} does not refer to {1}")
+MSG_DEF(JSMSG_DEBUG_WRAPPER_IN_WAY,   325, 2, JSEXN_TYPEERR, "{0} is a wrapper around {1}, but a direct reference is required")
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -4240,16 +4240,27 @@ DebuggerObject_makeDebuggeeValue(JSConte
     args.rval().set(args[0]);
     return true;
 }
 
 static bool
 RequireGlobalObject(JSContext *cx, HandleValue dbgobj, HandleObject obj)
 {
     if (!obj->isGlobal()) {
+        /* Help the poor programmer by pointing out wrappers around globals. */
+        if (obj->isWrapper()) {
+            JSObject *unwrapped = js::UnwrapObject(obj);
+            if (unwrapped->isGlobal()) {
+                js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_DEBUG_WRAPPER_IN_WAY,
+                                         JSDVG_SEARCH_STACK, dbgobj, NullPtr(),
+                                         "a global object", NULL);
+                return false;
+            }
+        }
+
         js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_DEBUG_BAD_REFERENT,
                                  JSDVG_SEARCH_STACK, dbgobj, NullPtr(),
                                  "a global object", NULL);
         return false;
     }
 
     return true;
 }