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
2 changes: 1 addition & 1 deletion Jint/Constraints/ConstraintsOptionsExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public static Options LimitMemory(this Options options, long memoryLimit)
{
options.WithoutConstraint(x => x is MemoryLimitConstraint);

if (memoryLimit > 0 && memoryLimit < int.MaxValue)
if (memoryLimit > 0 && memoryLimit < long.MaxValue)
{
options.Constraint(new MemoryLimitConstraint(memoryLimit));
}
Expand Down
46 changes: 27 additions & 19 deletions Jint/Constraints/MemoryLimitConstraint.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,22 @@ namespace Jint.Constraints;

public sealed class MemoryLimitConstraint : Constraint
{
private static readonly Func<long>? GetAllocatedBytesForCurrentThread;
private readonly long _memoryLimit;
private long _initialMemoryUsage;

#if !NET8_0_OR_GREATER
private static readonly Func<long>? _getAllocatedBytesForCurrentThread;

static MemoryLimitConstraint()
{
var methodInfo = typeof(GC).GetMethod("GetAllocatedBytesForCurrentThread");

if (methodInfo != null)
{
GetAllocatedBytesForCurrentThread = (Func<long>)Delegate.CreateDelegate(typeof(Func<long>), null, methodInfo);
_getAllocatedBytesForCurrentThread = (Func<long>) Delegate.CreateDelegate(typeof(Func<long>), null, methodInfo);
}
}
#endif

internal MemoryLimitConstraint(long memoryLimit)
{
Expand All @@ -25,28 +28,33 @@ internal MemoryLimitConstraint(long memoryLimit)

public override void Check()
{
if (_memoryLimit > 0)
if (_memoryLimit <= 0)
{
if (GetAllocatedBytesForCurrentThread != null)
{
var memoryUsage = GetAllocatedBytesForCurrentThread() - _initialMemoryUsage;
if (memoryUsage > _memoryLimit)
{
ExceptionHelper.ThrowMemoryLimitExceededException($"Script has allocated {memoryUsage} but is limited to {_memoryLimit}");
}
}
else
{
ExceptionHelper.ThrowPlatformNotSupportedException("The current platform doesn't support MemoryLimit.");
}
return;
}

#if NET8_0_OR_GREATER
var usage = GC.GetAllocatedBytesForCurrentThread();
#else
if (_getAllocatedBytesForCurrentThread == null)
{
ExceptionHelper.ThrowPlatformNotSupportedException("The current platform doesn't support MemoryLimit.");
}

var usage = _getAllocatedBytesForCurrentThread();
#endif
if (usage - _initialMemoryUsage > _memoryLimit)
{
ExceptionHelper.ThrowMemoryLimitExceededException($"Script has allocated {usage - _initialMemoryUsage} but is limited to {_memoryLimit}");
}
}

public override void Reset()
{
if (GetAllocatedBytesForCurrentThread != null)
{
_initialMemoryUsage = GetAllocatedBytesForCurrentThread();
}
#if NET8_0_OR_GREATER
_initialMemoryUsage = GC.GetAllocatedBytesForCurrentThread();
#else
_initialMemoryUsage = _getAllocatedBytesForCurrentThread?.Invoke() ?? 0;
#endif
}
}