Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions Jint.Tests/Runtime/ExecutionConstraintTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,41 @@ public void ShouldLimitArraySizeForJoin()
Assert.Throws<MemoryLimitExceededException>(() => engine.Evaluate("new Array(2147483647).join('*')"));
}

[Fact]
public void ShouldLimitTypedArraySizeForFill()
{
var engine = new Engine(o => o.MaxStatements(1_000).LimitMemory(4_000_000));
Assert.Throws<MemoryLimitExceededException>(() => engine.Evaluate("var arr = new Uint8Array(100000000); arr.fill(255);"));
}

[Fact]
public void ShouldLimitTypedArraySizeForCopyWithin()
{
var engine = new Engine(o => o.MaxStatements(1_000).LimitMemory(4_000_000));
Assert.Throws<MemoryLimitExceededException>(() => engine.Evaluate("var arr = new Uint8Array(100000000); arr[0] = 1; arr.copyWithin(1, 0);"));
}

[Fact]
public void ShouldLimitTypedArraySizeForReverse()
{
var engine = new Engine(o => o.MaxStatements(1_000).LimitMemory(4_000_000));
Assert.Throws<MemoryLimitExceededException>(() => engine.Evaluate("var arr = new Uint8Array(100000000); arr.reverse();"));
}

[Fact]
public void ShouldLimitTypedArraySizeForToReversed()
{
var engine = new Engine(o => o.MaxStatements(1_000).LimitMemory(4_000_000));
Assert.Throws<MemoryLimitExceededException>(() => engine.Evaluate("var arr = new Uint8Array(100000000); arr.toReversed();"));
}

[Fact]
public void ShouldLimitTypedArraySizeForWith()
{
var engine = new Engine(o => o.MaxStatements(1_000).LimitMemory(4_000_000));
Assert.Throws<MemoryLimitExceededException>(() => engine.Evaluate("var arr = new Uint8Array(100000000); arr.with(0, 1);"));
}

[Fact]
public void ShouldConsiderConstraintsWhenCallingInvoke()
{
Expand Down
33 changes: 33 additions & 0 deletions Jint/Native/Array/ArrayPrototype.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ namespace Jint.Native.Array;
/// </summary>
public sealed class ArrayPrototype : ArrayInstance
{
private const int ConstraintCheckInterval = 10_000;

private readonly Realm _realm;
private readonly ArrayConstructor _constructor;
private readonly ObjectTraverseStack _joinStack;
Expand Down Expand Up @@ -169,6 +171,12 @@ private ObjectInstance With(JsValue thisObject, JsCallArguments arguments)
{
a[k] = k == (ulong) actualIndex ? value : o.Get(k);
k++;

// Check constraints periodically to prevent long-running operations
if (k > 0 && k % ConstraintCheckInterval == 0)
{
_engine.Constraints.Check();
}
}
return new JsArray(_engine, a);
}
Expand Down Expand Up @@ -229,9 +237,15 @@ private JsValue Fill(JsValue thisObject, JsCallArguments arguments)
final = (ulong) System.Math.Min(relativeEnd, length);
}

// Check constraints periodically to prevent memory exhaustion in large fills
for (var i = k; i < final; ++i)
{
operations.Set(i, value, throwOnError: false);

if (i > k && (i - k) % ConstraintCheckInterval == 0)
{
_engine.Constraints.Check();
}
}

return o;
Expand Down Expand Up @@ -290,6 +304,7 @@ private JsValue CopyWithin(JsValue thisObject, JsCallArguments arguments)
}

var count = (long) System.Math.Min(final - from, len - to);
var initialCount = count;

long direction = 1;

Expand All @@ -315,6 +330,12 @@ private JsValue CopyWithin(JsValue thisObject, JsCallArguments arguments)
from += direction;
to += direction;
count--;

// Check constraints periodically to prevent long-running operations
if ((initialCount - count) % ConstraintCheckInterval == 0)
{
_engine.Constraints.Check();
}
}

return o;
Expand Down Expand Up @@ -1255,6 +1276,12 @@ private JsValue Reverse(JsValue thisObject, JsCallArguments arguments)
}

lower++;

// Check constraints periodically to prevent long-running operations
if (lower > 0 && lower % ConstraintCheckInterval == 0)
{
_engine.Constraints.Check();
}
}

return o.Target;
Expand Down Expand Up @@ -1441,6 +1468,12 @@ private JsValue ToReversed(JsValue thisObject, JsCallArguments arguments)
{
var from = len - k - 1;
a[k++] = o.Get(from);

// Check constraints periodically to prevent long-running operations
if (k > 0 && k % ConstraintCheckInterval == 0)
{
_engine.Constraints.Check();
}
}
return new JsArray(_engine, a);
}
Expand Down
33 changes: 33 additions & 0 deletions Jint/Native/TypedArray/IntrinsicTypedArrayPrototype.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ namespace Jint.Native.TypedArray;
/// </summary>
internal sealed class IntrinsicTypedArrayPrototype : Prototype
{
private const int ConstraintCheckInterval = 10_000;

private readonly IntrinsicTypedArrayConstructor _constructor;
private ClrFunction? _originalIteratorFunction;

Expand Down Expand Up @@ -366,6 +368,7 @@ private JsValue CopyWithin(JsValue thisObject, JsCallArguments arguments)
direction = 1;
}

var initialCountBytes = countBytes;
while (countBytes > 0)
{
if (fromByteIndex < bufferByteLimit && toByteIndex < bufferByteLimit)
Expand All @@ -375,6 +378,12 @@ private JsValue CopyWithin(JsValue thisObject, JsCallArguments arguments)
fromByteIndex += direction;
toByteIndex += direction;
countBytes--;

// Check constraints periodically to prevent long-running operations
if ((initialCountBytes - countBytes) % ConstraintCheckInterval == 0)
{
_engine.Constraints.Check();
}
}
else
{
Expand Down Expand Up @@ -497,6 +506,12 @@ private JsValue Fill(JsValue thisObject, JsCallArguments arguments)
for (var i = k; i < endIndex; ++i)
{
o[i] = value;

// Check constraints periodically to prevent memory exhaustion in large fills
if (i > k && (i - k) % ConstraintCheckInterval == 0)
{
_engine.Constraints.Check();
}
}

return thisObject;
Expand Down Expand Up @@ -996,6 +1011,12 @@ private ObjectInstance Reverse(JsValue thisObject, JsCallArguments arguments)
o[upper] = lowerValue;

lower++;

// Check constraints periodically to prevent long-running operations
if (lower > 0 && lower % ConstraintCheckInterval == 0)
{
_engine.Constraints.Check();
}
}

return o;
Expand Down Expand Up @@ -1506,6 +1527,12 @@ private JsValue ToReversed(JsValue thisObject, JsCallArguments arguments)
{
var from = len - k - 1;
a[k++] = o.Get(from);

// Check constraints periodically to prevent long-running operations
if (k > 0 && k % ConstraintCheckInterval == 0)
{
_engine.Constraints.Check();
}
}

return a;
Expand Down Expand Up @@ -1568,6 +1595,12 @@ private ObjectInstance With(JsValue thisObject, JsCallArguments arguments)
{
a[k] = k == (int) actualIndex ? value : o.Get(k);
k++;

// Check constraints periodically to prevent long-running operations
if (k > 0 && k % ConstraintCheckInterval == 0)
{
_engine.Constraints.Check();
}
}

return a;
Expand Down