Bug 650161 - Fix interaction between getDebuggees and compactings GC r=terrence
authorJon Coppeard <jcoppeard@mozilla.com>
Mon, 20 Oct 2014 09:07:42 +0100
changeset 211201 275d7eee096e5c64ecb013e63fd44c2bc6b14576
parent 211200 554d8083b8c6d0f454033b030192823ed5b92575
child 211202 79b3a9ac83578e145180f8a09332ea18e8f2b9d1
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersterrence
bugs650161
milestone36.0a1
Bug 650161 - Fix interaction between getDebuggees and compactings GC r=terrence
js/src/vm/Debugger.cpp
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -2225,27 +2225,41 @@ Debugger::hasDebuggee(JSContext *cx, uns
     args.rval().setBoolean(!!dbg->debuggees.lookup(global));
     return true;
 }
 
 /* static */ bool
 Debugger::getDebuggees(JSContext *cx, unsigned argc, Value *vp)
 {
     THIS_DEBUGGER(cx, argc, vp, "getDebuggees", args, dbg);
-    RootedArrayObject arrobj(cx, NewDenseFullyAllocatedArray(cx, dbg->debuggees.count()));
+
+    // Obtain the list of debuggees before wrapping each debuggee, as a GC could
+    // update the debuggees set while we are iterating it.
+    unsigned count = dbg->debuggees.count();
+    AutoValueVector debuggees(cx);
+    if (!debuggees.resize(count))
+        return false;
+    unsigned i = 0;
+    {
+        JS::AutoCheckCannotGC nogc;
+        for (GlobalObjectSet::Enum e(dbg->debuggees); !e.empty(); e.popFront())
+            debuggees[i++].setObject(*e.front());
+    }
+
+    RootedArrayObject arrobj(cx, NewDenseFullyAllocatedArray(cx, count));
     if (!arrobj)
         return false;
-    arrobj->ensureDenseInitializedLength(cx, 0, dbg->debuggees.count());
-    unsigned i = 0;
-    for (GlobalObjectSet::Enum e(dbg->debuggees); !e.empty(); e.popFront()) {
-        RootedValue v(cx, ObjectValue(*e.front()));
+    arrobj->ensureDenseInitializedLength(cx, 0, count);
+    for (i = 0; i < count; i++) {
+        RootedValue v(cx, debuggees[i]);
         if (!dbg->wrapDebuggeeValue(cx, &v))
             return false;
-        arrobj->setDenseElement(i++, v);
-    }
+        arrobj->setDenseElement(i, v);
+    }
+
     args.rval().setObject(*arrobj);
     return true;
 }
 
 /* static */ bool
 Debugger::getNewestFrame(JSContext *cx, unsigned argc, Value *vp)
 {
     THIS_DEBUGGER(cx, argc, vp, "getNewestFrame", args, dbg);