Bug 1152550 - Make sure that cross-global Iterator can not be broken. r=Waldo, a=sledru
authorTom Schuster <evilpies@gmail.com>
Sun, 19 Apr 2015 18:13:59 +0200
changeset 260265 2025aa8c5b1b
parent 260264 78c6b3ce2ce2
child 260266 fd5c74651fb2
push id731
push userryanvm@gmail.com
push date2015-04-24 19:52 +0000
treeherdermozilla-release@38ff61772a2e [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,45 @@ 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, NewFunctionWithProto(cx, NullPtr(), iterator_next, 0,
+                                                     JSFunction::NATIVE_FUN, NullPtr(),
+                                                     HandlePropertyName(cx->names().next),
+                                                     NullPtr()));
+        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)