GlobalObject::getOrCreateDebuggers must be called in the global object's compartment, since it may create an object.
authorJason Orendorff <jorendorff@mozilla.com>
Mon, 20 Jun 2011 14:06:42 -0500
changeset 74477 e05d3da5866a594138b9678d12bc122a81551946
parent 74476 ac45a3dbfe3304dca3b9c9b0de4464f1e102a0b3
child 74478 3a7a75064ce6b91d69ab70486a5df0cfd112eea3
push id2
push userbsmedberg@mozilla.com
push dateFri, 19 Aug 2011 14:38:13 +0000
milestone7.0a1
GlobalObject::getOrCreateDebuggers must be called in the global object's compartment, since it may create an object.
js/src/jit-test/tests/debug/gc-compartment-01.js
js/src/jit-test/tests/debug/gc-compartment-02.js
js/src/jsdbg.cpp
js/src/vm/GlobalObject.cpp
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/gc-compartment-01.js
@@ -0,0 +1,6 @@
+// A debugger can survive per-compartment GC.
+
+var g = newGlobal('new-compartment');
+var dbg = Debug(g);
+gc(g);
+gc(this);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/gc-compartment-02.js
@@ -0,0 +1,13 @@
+// Referents of Debug.Objects in other compartments always survive per-compartment GC.
+
+var g = newGlobal('new-compartment');
+var dbg = Debug(g);
+var arr = [];
+dbg.hooks = {debuggerHandler: function (frame) { arr.push(frame.eval("[]").return); }};
+g.eval("for (var i = 0; i < 10; i++) debugger;");
+assertEq(arr.length, 10);
+
+gc(g);
+
+for (var i = 0; i < arr.length; i++)
+    assertEq(arr[i].class, "Array");
--- a/js/src/jsdbg.cpp
+++ b/js/src/jsdbg.cpp
@@ -957,16 +957,19 @@ Debug::addDebuggeeGlobal(JSContext *cx, 
                 if (visited.find(next) == visited.end() && !visited.append(next))
                     return false;
             }
         }
     }
 
     // Each debugger-debuggee relation must be stored in up to three places.
     // JSCompartment::addDebuggee enables debug mode if needed.
+    AutoCompartment ac(cx, obj);
+    if (!ac.enter())
+        return false;
     GlobalObject::DebugVector *v = obj->getOrCreateDebuggers(cx);
     if (!v || !v->append(this)) {
         js_ReportOutOfMemory(cx);
         goto fail1;
     }
     if (!debuggees.put(obj)) {
         js_ReportOutOfMemory(cx);
         goto fail2;
--- a/js/src/vm/GlobalObject.cpp
+++ b/js/src/vm/GlobalObject.cpp
@@ -222,16 +222,17 @@ GlobalObject::getDebuggers()
         return NULL;
     JS_ASSERT(debuggers.toObject().clasp == &GlobalDebuggees_class);
     return (DebugVector *) debuggers.toObject().getPrivate();
 }
 
 GlobalObject::DebugVector *
 GlobalObject::getOrCreateDebuggers(JSContext *cx)
 {
+    assertSameCompartment(cx, this);
     DebugVector *vec = getDebuggers();
     if (vec)
         return vec;
 
     JSObject *obj = NewNonFunction<WithProto::Given>(cx, &GlobalDebuggees_class, NULL, NULL);
     if (!obj)
         return NULL;
     vec = cx->new_<DebugVector>();