Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor options and add MaxArraySize constraint #923

Merged
merged 1 commit into from
Sep 10, 2021
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
Refactor options and add MaxArraySize constraint
  • Loading branch information
lahma committed Sep 10, 2021
commit cee8f8c7f6ce0340d44796afce972dcc8ac3abd6
254 changes: 0 additions & 254 deletions Jint.Tests/Runtime/EngineTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Threading;
using Esprima;
using Esprima.Ast;
using Jint.Native;
Expand Down Expand Up @@ -754,259 +753,6 @@ public void ShouldNotExecuteDebuggerStatement()
new Engine().Evaluate("debugger");
}

[Fact]
public void ShouldThrowStatementCountOverflow()
{
Assert.Throws<StatementsCountOverflowException>(
() => new Engine(cfg => cfg.MaxStatements(100)).Evaluate("while(true);")
);
}

[Fact]
public void ShouldThrowMemoryLimitExceeded()
{
Assert.Throws<MemoryLimitExceededException>(
() => new Engine(cfg => cfg.LimitMemory(2048)).Evaluate("a=[]; while(true){ a.push(0); }")
);
}

[Fact]
public void ShouldThrowTimeout()
{
Assert.Throws<TimeoutException>(
() => new Engine(cfg => cfg.TimeoutInterval(new TimeSpan(0, 0, 0, 0, 500))).Evaluate("while(true);")
);
}

[Fact]
public void ShouldThrowExecutionCanceled()
{
Assert.Throws<ExecutionCanceledException>(
() =>
{
using (var tcs = new CancellationTokenSource())
using (var waitHandle = new ManualResetEvent(false))
{
var engine = new Engine(cfg => cfg.CancellationToken(tcs.Token));

ThreadPool.QueueUserWorkItem(state =>
{
waitHandle.WaitOne();
tcs.Cancel();
});

engine.SetValue("waitHandle", waitHandle);
engine.Evaluate(@"
function sleep(millisecondsTimeout) {
var totalMilliseconds = new Date().getTime() + millisecondsTimeout;

while (new Date() < totalMilliseconds) { }
}

sleep(100);
waitHandle.Set();
sleep(5000);
");
}
}
);
}


[Fact]
public void CanDiscardRecursion()
{
var script = @"var factorial = function(n) {
if (n>1) {
return n * factorial(n - 1);
}
};

var result = factorial(500);
";

Assert.Throws<RecursionDepthOverflowException>(
() => new Engine(cfg => cfg.LimitRecursion()).Execute(script)
);
}

[Fact]
public void ShouldDiscardHiddenRecursion()
{
var script = @"var renamedFunc;
var exec = function(callback) {
renamedFunc = callback;
callback();
};

var result = exec(function() {
renamedFunc();
});
";

Assert.Throws<RecursionDepthOverflowException>(
() => new Engine(cfg => cfg.LimitRecursion()).Execute(script)
);
}

[Fact]
public void ShouldRecognizeAndDiscardChainedRecursion()
{
var script = @" var funcRoot, funcA, funcB, funcC, funcD;

var funcRoot = function() {
funcA();
};

var funcA = function() {
funcB();
};

var funcB = function() {
funcC();
};

var funcC = function() {
funcD();
};

var funcD = function() {
funcRoot();
};

funcRoot();
";

Assert.Throws<RecursionDepthOverflowException>(
() => new Engine(cfg => cfg.LimitRecursion()).Execute(script)
);
}

[Fact]
public void ShouldProvideCallChainWhenDiscardRecursion()
{
var script = @" var funcRoot, funcA, funcB, funcC, funcD;

var funcRoot = function() {
funcA();
};

var funcA = function() {
funcB();
};

var funcB = function() {
funcC();
};

var funcC = function() {
funcD();
};

var funcD = function() {
funcRoot();
};

funcRoot();
";

RecursionDepthOverflowException exception = null;

try
{
new Engine(cfg => cfg.LimitRecursion()).Execute(script);
}
catch (RecursionDepthOverflowException ex)
{
exception = ex;
}

Assert.NotNull(exception);
Assert.Equal("funcRoot->funcA->funcB->funcC->funcD", exception.CallChain);
Assert.Equal("funcRoot", exception.CallExpressionReference);
}

[Fact]
public void ShouldAllowShallowRecursion()
{
var script = @"var factorial = function(n) {
if (n>1) {
return n * factorial(n - 1);
}
};

var result = factorial(8);
";

new Engine(cfg => cfg.LimitRecursion(20)).Execute(script);
}

[Fact]
public void ShouldDiscardDeepRecursion()
{
var script = @"var factorial = function(n) {
if (n>1) {
return n * factorial(n - 1);
}
};

var result = factorial(38);
";

Assert.Throws<RecursionDepthOverflowException>(
() => new Engine(cfg => cfg.LimitRecursion(20)).Execute(script)
);
}

[Fact]
public void ShouldAllowRecursionLimitWithoutReferencedName()
{
const string input = @"(function () {
var factorial = function(n) {
if (n>1) {
return n * factorial(n - 1);
}
};

var result = factorial(38);
})();
";

var engine = new Engine(o => o.LimitRecursion(20));
Assert.Throws<RecursionDepthOverflowException>(() => engine.Execute(input));
}

[Fact]
public void ShouldLimitRecursionWithAllFunctionInstances()
{
var engine = new Engine(cfg =>
{
// Limit recursion to 5 invocations
cfg.LimitRecursion(5);
cfg.Strict();
});

var ex = Assert.Throws<RecursionDepthOverflowException>(() => engine.Evaluate(@"
var myarr = new Array(5000);
for (var i = 0; i < myarr.length; i++) {
myarr[i] = function(i) {
myarr[i + 1](i + 1);
}
}

myarr[0](0);
"));
}

[Fact]
public void ShouldLimitRecursionWithGetters()
{
const string code = @"var obj = { get test() { return this.test + '2'; } }; obj.test;";
var engine = new Engine(cfg => cfg.LimitRecursion(10));

Assert.Throws<RecursionDepthOverflowException>(() => engine.Evaluate(code));
}

[Fact]
public void ShouldConvertDoubleToStringWithoutLosingPrecision()
{
Expand Down
Loading