2
0
Эх сурвалжийг харах

[1.4>master] [MERGE #2374 @akroshg] Proxy : fixing a case related to GetOwnProperty.

Merge pull request #2374 from akroshg:proxy

According to OridinarySet(9.1.9.1) if the proxy returns the existing reciever we need to apply few checks and return from there.
Let existingDescriptor be ? Receiver.[[GetOwnProperty]](P).
If existingDescriptor is not undefined, then
    If IsAccessorDescriptor(existingDescriptor) is true, return false.
    If existingDescriptor.[[Writable]] is false, return false.

Fixed the codebase now, which fixes one assert as well.
Akrosh Gandhi 9 жил өмнө
parent
commit
7f1e1d0834

+ 15 - 0
lib/Runtime/Library/JavascriptProxy.cpp

@@ -645,6 +645,21 @@ namespace Js
         }
         else
         {
+            // ES2017 Spec'ed (9.1.9.1): 
+            // If existingDescriptor is not undefined, then
+            //    If IsAccessorDescriptor(existingDescriptor) is true, return false.
+            //    If existingDescriptor.[[Writable]] is false, return false.
+
+            if (proxyPropertyDescriptor.IsAccessorDescriptor())
+            {
+                return FALSE;
+            }
+
+            if (proxyPropertyDescriptor.WritableSpecified() && !proxyPropertyDescriptor.IsWritable())
+            {
+                return FALSE;
+            }
+
             proxyPropertyDescriptor.SetValue(value);
             proxyPropertyDescriptor.SetOriginal(nullptr);
             return Js::JavascriptOperators::DefineOwnPropertyDescriptor(this, propertyId, proxyPropertyDescriptor, true, scriptContext);

+ 64 - 0
test/es6/proxybugs.js

@@ -37,6 +37,70 @@ var tests = [
                 assert.areEqual(target.x, 20, "target object should work as expected even after proxy object is added to map");
             });
         }
+    },
+    {
+        name: "Assertion validation : returning descriptor during getOwnPropertyDescriptor should not pollute the descriptor",
+        body() {
+            var target = {};
+            var handler = {};
+            var getOwnPropertyDescriptorCalled = false;
+            handler['defineProperty'] = function () {
+                assert.fail("This function will not be called as 'getOwnPropertyDescriptor' will add accessor");
+            };
+            
+            handler['getOwnPropertyDescriptor'] = function (t, property) {
+                getOwnPropertyDescriptorCalled = true;
+                Object.defineProperty(t, 'abc', { set: function () { } });
+                return Reflect.getOwnPropertyDescriptor(t, property);
+            };
+            
+            var proxy = new Proxy(target, handler);
+            proxy.abc = undefined;
+            assert.isTrue(getOwnPropertyDescriptorCalled);
+        }
+    },
+    {
+        name: "Assertion validation : returning descriptor with writable false should not defineProperty again.",
+        body() {
+            var target = {};
+            var handler = {};
+            var getOwnPropertyDescriptorCalled = false;
+            handler['defineProperty'] = function () {
+                assert.fail("This function will not be called as 'getOwnPropertyDescriptor' will add property with writable false");
+            };
+            
+            handler['getOwnPropertyDescriptor'] = function (t, property) {
+                getOwnPropertyDescriptorCalled = true;
+                Object.defineProperty(t, 'abc', { value : 1, writable : false });
+                return Reflect.getOwnPropertyDescriptor(t, property);
+            };
+            
+            var proxy = new Proxy(target, handler);
+            proxy.abc = undefined;
+            assert.isTrue(getOwnPropertyDescriptorCalled);
+        }
+    },
+    {
+        name: "No property found at getOwnPropertyDescriptor will call defineProperty",
+        body() {
+            var target = {};
+            var handler = {};
+            var definePropertyCalled = false;
+            var getOwnPropertyDescriptorCalled = false;
+            handler['defineProperty'] = function () {
+                definePropertyCalled = true;
+            };
+            
+            handler['getOwnPropertyDescriptor'] = function (t, property) {
+                getOwnPropertyDescriptorCalled = true;
+                return Reflect.getOwnPropertyDescriptor(t, property);
+            };
+            
+            var proxy = new Proxy(target, handler);
+            proxy.abc = undefined;
+            assert.isTrue(definePropertyCalled);
+            assert.isTrue(getOwnPropertyDescriptorCalled);
+        }
     }
 ];