Bug 1152550 - Make sure that cross-global Iterator can not be broken. r=Waldo, a=sledru
💩💩 backed out by d20a4e36e508 💩 💩
authorTom Schuster <evilpies@gmail.com>
Sun, 19 Apr 2015 18:13:59 +0200
changeset 260250 6b096f9b31d3
parent 260249 b7d8d79c1ee5
child 260251 da1d9ba28360
push id727
push userryanvm@gmail.com
push date2015-04-23 14:45 +0000
treeherdermozilla-release@7c66212e4c09 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersWaldo, sledru
bugs1152550
milestone38.0
Bug 1152550 - Make sure that cross-global Iterator can not be broken. r=Waldo, a=sledru
js/src/jit-test/tests/basic/cross-global-for-in.js
js/src/jsiter.cpp
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/cross-global-for-in.js
@@ -0,0 +1,11 @@
+var global = newGlobal();
+
+var arrayIter = (new global.Array())[global.Symbol.iterator]();
+var ArrayIteratorPrototype = Object.getPrototypeOf(arrayIter);
+var arrayIterProtoBase = Object.getPrototypeOf(ArrayIteratorPrototype);
+var IteratorPrototype = arrayIterProtoBase;
+delete IteratorPrototype.next;
+
+var obj = global.eval('({a: 1})')
+for (var x in obj) {}
+assertEq(x, "a");
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -472,16 +472,18 @@ Compare(T* a, T* b, size_t c)
       case 3:      if (*a++ != *b++) return false;
       case 2:      if (*a++ != *b++) return false;
       case 1:      if (*a++ != *b++) return false;
               } while (--n > 0);
     }
     return true;
 }
 
+static bool iterator_next(JSContext* cx, unsigned argc, Value* vp);
+
 static inline PropertyIteratorObject*
 NewPropertyIteratorObject(JSContext* cx, unsigned flags)
 {
     if (flags & JSITER_ENUMERATE) {
         RootedObjectGroup group(cx, ObjectGroup::defaultNewGroup(cx, &PropertyIteratorObject::class_,
                                                                  TaggedProto(nullptr)));
         if (!group)
             return nullptr;
@@ -495,23 +497,43 @@ NewPropertyIteratorObject(JSContext* cx,
                                                           ITERATOR_FINALIZE_KIND));
         if (!shape)
             return nullptr;
 
         JSObject* obj = JSObject::create(cx, ITERATOR_FINALIZE_KIND,
                                          GetInitialHeap(GenericObject, clasp), shape, group);
         if (!obj)
             return nullptr;
+
         PropertyIteratorObject* res = &obj->as<PropertyIteratorObject>();
 
         MOZ_ASSERT(res->numFixedSlots() == JSObject::ITER_CLASS_NFIXED_SLOTS);
         return res;
     }
 
-    return NewBuiltinClassInstance<PropertyIteratorObject>(cx);
+    Rooted<PropertyIteratorObject*> res(cx, NewBuiltinClassInstance<PropertyIteratorObject>(cx));
+    if (!res)
+        return nullptr;
+
+    if (flags == 0) {
+        // Redefine next as an own property. This ensure that deleting the
+        // next method on the prototype doesn't break cross-global for .. in.
+        // We don't have to do this for JSITER_ENUMERATE because that object always
+        // takes an optimized path.
+        RootedFunction next(cx, NewNativeFunction(cx, iterator_next, 0,
+                                                  HandlePropertyName(cx->names().next)));
+        if (!next)
+            return nullptr;
+
+        RootedValue value(cx, ObjectValue(*next));
+        if (!DefineProperty(cx, res, cx->names().next, value))
+            return nullptr;
+    }
+
+    return res;
 }
 
 NativeIterator*
 NativeIterator::allocateIterator(JSContext* cx, uint32_t slength, const AutoIdVector& props)
 {
     size_t plength = props.length();
     NativeIterator* ni = cx->zone()->pod_malloc_with_extra<NativeIterator, void*>(plength + slength);
     if (!ni)