Bug 1369680 - Use HasOwnProperty when resolving lazy properties to avoid triggering proxy traps in the proto-chain. r=jandem
authorAndré Bargull <andre.bargull@gmail.com>
Fri, 02 Jun 2017 16:11:42 +0200
changeset 362521 a6aa43c2ff31fa0b58c3ac097affb59013641e75
parent 362520 3825fc840a68526654858e782d9f8fed6d68d78c
child 362522 45eded6a52c0bfa75cc7515579fd678e99572832
push id91103
push userryanvm@gmail.com
push dateTue, 06 Jun 2017 14:02:54 +0000
treeherdermozilla-inbound@a6aa43c2ff31 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem
bugs1369680
milestone55.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1369680 - Use HasOwnProperty when resolving lazy properties to avoid triggering proxy traps in the proto-chain. r=jandem
js/src/jsfun.cpp
js/src/tests/ecma_6/Proxy/proxy-proto-lazy-props.js
js/src/vm/ArgumentsObject.cpp
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -72,26 +72,26 @@ fun_enumerate(JSContext* cx, HandleObjec
 {
     MOZ_ASSERT(obj->is<JSFunction>());
 
     RootedId id(cx);
     bool found;
 
     if (!obj->isBoundFunction() && !obj->as<JSFunction>().isArrow()) {
         id = NameToId(cx->names().prototype);
-        if (!HasProperty(cx, obj, id, &found))
+        if (!HasOwnProperty(cx, obj, id, &found))
             return false;
     }
 
     id = NameToId(cx->names().length);
-    if (!HasProperty(cx, obj, id, &found))
+    if (!HasOwnProperty(cx, obj, id, &found))
         return false;
 
     id = NameToId(cx->names().name);
-    if (!HasProperty(cx, obj, id, &found))
+    if (!HasOwnProperty(cx, obj, id, &found))
         return false;
 
     return true;
 }
 
 bool
 IsFunction(HandleValue v)
 {
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_6/Proxy/proxy-proto-lazy-props.js
@@ -0,0 +1,63 @@
+function makeProxyPrototype(target) {
+    return Object.setPrototypeOf(target, new Proxy({}, new Proxy({
+        getPrototypeOf() {
+            return null;
+        },
+        ownKeys() {
+            return [];
+        },
+        get(t, pk, r) {
+            // Handle the non-standard __iterator__ hook.
+            if (pk !== "__iterator__")
+                throw new Error("Unexpected [[Get]]: " + String(pk));
+        }
+    }, {
+        get(t, pk, r) {
+            if (pk in t)
+                return Reflect.get(t, pk, r);
+            throw new Error("Unexpected trap called: " + pk);
+        }
+    })));
+}
+
+function enumerateMappedArgs(x) {
+    var a = makeProxyPrototype(arguments);
+
+    // Delete all lazy properties and ensure no [[Has]] trap is called for them
+    // on the prototype chain.
+    delete a.length;
+    delete a.callee;
+    delete a[Symbol.iterator];
+    delete a[0];
+
+    for (var k in a);
+}
+enumerateMappedArgs(0);
+
+function enumerateUnmappedArgs(x) {
+    "use strict";
+    var a = makeProxyPrototype(arguments);
+
+    delete a.length;
+    // delete a.callee; // .callee is non-configurable
+    delete a[Symbol.iterator];
+    delete a[0];
+
+    for (var k in a);
+}
+enumerateUnmappedArgs(0);
+
+function enumerateFunction() {
+    var f = makeProxyPrototype(function named() {});
+
+    // delete f.prototype; // .prototype is non-configurable
+    delete f.length;
+    delete f.name;
+
+    for (var k in f);
+}
+enumerateFunction();
+
+
+if (typeof reportCompare === "function")
+    reportCompare(0, 0);
--- a/js/src/vm/ArgumentsObject.cpp
+++ b/js/src/vm/ArgumentsObject.cpp
@@ -608,30 +608,30 @@ MappedArgumentsObject::obj_enumerate(JSC
 {
     Rooted<MappedArgumentsObject*> argsobj(cx, &obj->as<MappedArgumentsObject>());
 
     RootedId id(cx);
     bool found;
 
     // Trigger reflection.
     id = NameToId(cx->names().length);
-    if (!HasProperty(cx, argsobj, id, &found))
+    if (!HasOwnProperty(cx, argsobj, id, &found))
         return false;
 
     id = NameToId(cx->names().callee);
-    if (!HasProperty(cx, argsobj, id, &found))
+    if (!HasOwnProperty(cx, argsobj, id, &found))
         return false;
 
     id = SYMBOL_TO_JSID(cx->wellKnownSymbols().iterator);
-    if (!HasProperty(cx, argsobj, id, &found))
+    if (!HasOwnProperty(cx, argsobj, id, &found))
         return false;
 
     for (unsigned i = 0; i < argsobj->initialLength(); i++) {
         id = INT_TO_JSID(i);
-        if (!HasProperty(cx, argsobj, id, &found))
+        if (!HasOwnProperty(cx, argsobj, id, &found))
             return false;
     }
 
     return true;
 }
 
 // ES 2017 draft 9.4.4.2
 /* static */ bool
@@ -798,30 +798,30 @@ UnmappedArgumentsObject::obj_enumerate(J
 {
     Rooted<UnmappedArgumentsObject*> argsobj(cx, &obj->as<UnmappedArgumentsObject>());
 
     RootedId id(cx);
     bool found;
 
     // Trigger reflection.
     id = NameToId(cx->names().length);
-    if (!HasProperty(cx, argsobj, id, &found))
+    if (!HasOwnProperty(cx, argsobj, id, &found))
         return false;
 
     id = NameToId(cx->names().callee);
-    if (!HasProperty(cx, argsobj, id, &found))
+    if (!HasOwnProperty(cx, argsobj, id, &found))
         return false;
 
     id = SYMBOL_TO_JSID(cx->wellKnownSymbols().iterator);
-    if (!HasProperty(cx, argsobj, id, &found))
+    if (!HasOwnProperty(cx, argsobj, id, &found))
         return false;
 
     for (unsigned i = 0; i < argsobj->initialLength(); i++) {
         id = INT_TO_JSID(i);
-        if (!HasProperty(cx, argsobj, id, &found))
+        if (!HasOwnProperty(cx, argsobj, id, &found))
             return false;
     }
 
     return true;
 }
 
 void
 ArgumentsObject::finalize(FreeOp* fop, JSObject* obj)