瀏覽代碼

Fix Array.prototype.toString() stackoverflow (#1976)

Roberto Blázquez 10 月之前
父節點
當前提交
0eee47d5c8
共有 3 個文件被更改,包括 43 次插入2 次删除
  1. 16 0
      Jint.Tests/Runtime/ArrayTests.cs
  2. 12 2
      Jint/Collections/ObjectTraverseStack.cs
  3. 15 0
      Jint/Native/Array/ArrayPrototype.cs

+ 16 - 0
Jint.Tests/Runtime/ArrayTests.cs

@@ -39,6 +39,22 @@ public class ArrayTests
         Assert.Equal("[object Object]", result);
     }
 
+    [Fact]
+    public void ArrayPrototypeJoinWithCircularReference()
+    {
+        var result = _engine.Evaluate("Array.prototype.join.call((c = [1, 2, 3, 4], b = [1, 2, 3, 4], b[1] = c, c[1] = b, c))").AsString();
+
+        Assert.Equal("1,1,,3,4,3,4", result);
+    }
+
+    [Fact]
+    public void ArrayPrototypeToLocaleStringWithCircularReference()
+    {
+        var result = _engine.Evaluate("Array.prototype.toLocaleString.call((c = [1, 2, 3, 4], b = [1, 2, 3, 4], b[1] = c, c[1] = b, c))").AsString();
+
+        Assert.Equal("1,1,,3,4,3,4", result);
+    }
+
     [Fact]
     public void EmptyStringKey()
     {

+ 12 - 2
Jint/Collections/ObjectTraverseStack.cs

@@ -16,7 +16,7 @@ internal sealed class ObjectTraverseStack
         _engine = engine;
     }
 
-    public void Enter(JsValue value)
+    public bool TryEnter(JsValue value)
     {
         if (value is null)
         {
@@ -25,10 +25,20 @@ internal sealed class ObjectTraverseStack
 
         if (_stack.Contains(value))
         {
-            ExceptionHelper.ThrowTypeError(_engine.Realm, "Cyclic reference detected.");
+            return false;
         }
 
         _stack.Push(value);
+
+        return true;
+    }
+
+    public void Enter(JsValue value)
+    {
+        if (!TryEnter(value))
+        {
+            ExceptionHelper.ThrowTypeError(_engine.Realm, "Cyclic reference detected.");
+        }
     }
 
     public void Exit()

+ 15 - 0
Jint/Native/Array/ArrayPrototype.cs

@@ -21,6 +21,7 @@ public sealed class ArrayPrototype : ArrayInstance
 {
     private readonly Realm _realm;
     private readonly ArrayConstructor _constructor;
+    private readonly ObjectTraverseStack _joinStack;
     internal ClrFunction? _originalIteratorFunction;
 
     internal ArrayPrototype(
@@ -33,6 +34,7 @@ public sealed class ArrayPrototype : ArrayInstance
         _length = new PropertyDescriptor(JsNumber.PositiveZero, PropertyFlag.Writable);
         _realm = realm;
         _constructor = arrayConstructor;
+        _joinStack = new(engine);
     }
 
     protected override void Initialize()
@@ -1273,6 +1275,11 @@ public sealed class ArrayPrototype : ArrayInstance
             return JsString.Empty;
         }
 
+        if (!_joinStack.TryEnter(thisObject))
+        {
+            return JsString.Empty;
+        }
+
         static string StringFromJsValue(JsValue value)
         {
             return value.IsNullOrUndefined()
@@ -1283,6 +1290,7 @@ public sealed class ArrayPrototype : ArrayInstance
         var s = StringFromJsValue(o.Get(0));
         if (len == 1)
         {
+            _joinStack.Exit();
             return s;
         }
 
@@ -1296,6 +1304,7 @@ public sealed class ArrayPrototype : ArrayInstance
             }
             sb.Append(StringFromJsValue(o.Get(k)));
         }
+        _joinStack.Exit();
 
         return sb.ToString();
     }
@@ -1314,6 +1323,11 @@ public sealed class ArrayPrototype : ArrayInstance
             return JsString.Empty;
         }
 
+        if (!_joinStack.TryEnter(thisObject))
+        {
+            return JsString.Empty;
+        }
+
         using var r = new ValueStringBuilder();
         for (uint k = 0; k < len; k++)
         {
@@ -1327,6 +1341,7 @@ public sealed class ArrayPrototype : ArrayInstance
                 r.Append(s);
             }
         }
+        _joinStack.Exit();
 
         return r.ToString();
     }