瀏覽代碼

Fix JSON-serialization issues (#1037)

Issues:
* function-valued properties should be excluded entirely from JSON, not serialized as objects
* proxies to functions are not handled correctly

Changes:
* Remove extraneous early exit case (JsonSerializer line 175) which diverges from the algorithm in the spec (https://tc39.es/ecma262/#sec-serializejsonproperty). This appears to correct the serialization of function-valued properties, but unmasks another issue where ProxyInstance is mistakenly treated as callable even when target is not
* Change "value is ICallbable" test to "value.IsCallable" so that serialization of ProxyInstance is handled correctly (according to the spec proxies are callable only if the target is callable - https://tc39.es/ecma262/#sec-proxycreate)
* Add test to verify serialization of function-valued properties
Jonathan Resnick 3 年之前
父節點
當前提交
8e8cae4fdf
共有 3 個文件被更改,包括 16 次插入7 次删除
  1. 14 0
      Jint.Tests/Runtime/EngineTests.cs
  2. 1 6
      Jint/Native/Json/JsonSerializer.cs
  3. 1 1
      Jint/Native/Proxy/ProxyInstance.cs

+ 14 - 0
Jint.Tests/Runtime/EngineTests.cs

@@ -2059,6 +2059,20 @@ var prep = function (fn) { fn(); };
             Assert.True(res == "Cyclic reference detected.");
         }
 
+        [Fact]
+        public void ShouldNotStringifyFunctionValuedProperties()
+        {
+            var engine = new Engine();
+            var res = engine.Evaluate(@"
+                var obj = {
+                    f: function() { }
+                };
+                return JSON.stringify(obj);
+            ");
+
+            Assert.Equal("{}", res.AsString());
+        }
+
         [Theory]
         [InlineData("", "escape('')")]
         [InlineData("%u0100%u0101%u0102", "escape('\u0100\u0101\u0102')")]

+ 1 - 6
Jint/Native/Json/JsonSerializer.cs

@@ -172,11 +172,6 @@ namespace Jint.Native.Json
                     case BigIntInstance bigIntInstance:
                         value = bigIntInstance.BigIntData;
                         break;
-                    default:
-                        value = SerializesAsArray(value)
-                            ? SerializeJSONArray(value)
-                            : SerializeJSONObject(value.AsObject());
-                        return value;
                 }
             }
 
@@ -211,7 +206,7 @@ namespace Jint.Native.Json
                 ExceptionHelper.ThrowTypeError(_engine.Realm, "Do not know how to serialize a BigInt");
             }
 
-            var isCallable = value.IsObject() && value.AsObject() is ICallable;
+            var isCallable = value.IsObject() && value.IsCallable;
 
             if (value.IsObject() && isCallable == false)
             {

+ 1 - 1
Jint/Native/Proxy/ProxyInstance.cs

@@ -445,7 +445,7 @@ namespace Jint.Native.Proxy
             return true;
         }
 
-        internal override bool IsCallable => _target is ICallable;
+        internal override bool IsCallable => _target is not null && _target.IsCallable;
 
         private bool TryCallHandler(JsValue propertyName, JsValue[] arguments, out JsValue result)
         {