Skip to content

Commit

Permalink
Fix Array.prototype.toString() stackoverflow (#1976)
Browse files Browse the repository at this point in the history
  • Loading branch information
xBaank authored Oct 6, 2024
1 parent 1fd4183 commit 0eee47d
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 2 deletions.
16 changes: 16 additions & 0 deletions Jint.Tests/Runtime/ArrayTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,22 @@ public void ArrayPrototypeToStringWithObject()
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()
{
Expand Down
14 changes: 12 additions & 2 deletions Jint/Collections/ObjectTraverseStack.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public ObjectTraverseStack(Engine engine)
_engine = engine;
}

public void Enter(JsValue value)
public bool TryEnter(JsValue value)
{
if (value is null)
{
Expand All @@ -25,10 +25,20 @@ public void Enter(JsValue value)

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()
Expand Down
15 changes: 15 additions & 0 deletions Jint/Native/Array/ArrayPrototype.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -33,6 +34,7 @@ internal ArrayPrototype(
_length = new PropertyDescriptor(JsNumber.PositiveZero, PropertyFlag.Writable);
_realm = realm;
_constructor = arrayConstructor;
_joinStack = new(engine);
}

protected override void Initialize()
Expand Down Expand Up @@ -1273,6 +1275,11 @@ private JsValue Join(JsValue thisObject, JsValue[] arguments)
return JsString.Empty;
}

if (!_joinStack.TryEnter(thisObject))
{
return JsString.Empty;
}

static string StringFromJsValue(JsValue value)
{
return value.IsNullOrUndefined()
Expand All @@ -1283,6 +1290,7 @@ static string StringFromJsValue(JsValue value)
var s = StringFromJsValue(o.Get(0));
if (len == 1)
{
_joinStack.Exit();
return s;
}

Expand All @@ -1296,6 +1304,7 @@ static string StringFromJsValue(JsValue value)
}
sb.Append(StringFromJsValue(o.Get(k)));
}
_joinStack.Exit();

return sb.ToString();
}
Expand All @@ -1314,6 +1323,11 @@ private JsValue ToLocaleString(JsValue thisObject, JsValue[] arguments)
return JsString.Empty;
}

if (!_joinStack.TryEnter(thisObject))
{
return JsString.Empty;
}

using var r = new ValueStringBuilder();
for (uint k = 0; k < len; k++)
{
Expand All @@ -1327,6 +1341,7 @@ private JsValue ToLocaleString(JsValue thisObject, JsValue[] arguments)
r.Append(s);
}
}
_joinStack.Exit();

return r.ToString();
}
Expand Down

0 comments on commit 0eee47d

Please sign in to comment.