Skip to content

Commit

Permalink
Timeout for regex. (#621)
Browse files Browse the repository at this point in the history
  • Loading branch information
SebastianStehle authored and sebastienros committed May 17, 2019
1 parent 5e0b3bb commit 6e06825
Show file tree
Hide file tree
Showing 6 changed files with 75 additions and 10 deletions.
34 changes: 34 additions & 0 deletions Jint.Tests/Runtime/RegExpTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using System;
using System.Text.RegularExpressions;
using Xunit;

namespace Jint.Tests.Runtime
{
public class RegExpTests
{
private readonly string testRegex = "^(https?:\\/\\/)?([\\da-z\\.-]+)\\.([a-z\\.]{2,6})([\\/\\w\\.-]*)*\\/?$";
private readonly string testedValue = "https://archiverbx.blob.core.windows.net/static/C:/Users/USR/Documents/Projects/PROJ/static/images/full/1234567890.jpg";

[Fact]
public void CanNotBreakEngineWithLongRunningMatch()
{
var engine = new Engine(e => e.RegexTimeoutInterval(TimeSpan.FromSeconds(1)));

Assert.Throws<RegexMatchTimeoutException>(() =>
{
engine.Execute($"'{testedValue}'.match(/{testRegex}/)");
});
}

[Fact]
public void CanNotBreakEngineWithLongRunningRegExp()
{
var engine = new Engine(e => e.RegexTimeoutInterval(TimeSpan.FromSeconds(1)));

Assert.Throws<RegexMatchTimeoutException>(() =>
{
engine.Execute($"'{testedValue}'.match(new RegExp(/{testRegex}/))");
});
}
}
}
2 changes: 1 addition & 1 deletion Jint/Engine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ public sealed class Engine
{ typeof(UInt16), (engine, v) => JsNumber.Create((UInt16)v) },
{ typeof(UInt32), (engine, v) => JsNumber.Create((UInt32)v) },
{ typeof(UInt64), (engine, v) => JsNumber.Create((UInt64)v) },
{ typeof(System.Text.RegularExpressions.Regex), (engine, v) => engine.RegExp.Construct((System.Text.RegularExpressions.Regex)v, "") }
{ typeof(System.Text.RegularExpressions.Regex), (engine, v) => engine.RegExp.Construct((System.Text.RegularExpressions.Regex)v, "", engine) }
};

// shared frozen version
Expand Down
8 changes: 4 additions & 4 deletions Jint/JsValueExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public static bool AsBoolean(this JsValue value)
{
if (value._type != Types.Boolean)
{
ExceptionHelper.ThrowArgumentException("The value is not a boolean");
ExceptionHelper.ThrowArgumentException($"Expected boolean but got {value._type}");
}

return ((JsBoolean) value)._value;
Expand All @@ -22,7 +22,7 @@ public static double AsNumber(this JsValue value)
{
if (value._type != Types.Number)
{
ExceptionHelper.ThrowArgumentException("The value is not a number");
ExceptionHelper.ThrowArgumentException($"Expected number but got {value._type}");
}

return ((JsNumber) value)._value;
Expand All @@ -33,7 +33,7 @@ public static string AsString(this JsValue value)
{
if (value._type != Types.String)
{
ExceptionHelper.ThrowArgumentException("The value is not a string");
ExceptionHelper.ThrowArgumentException($"Expected string but got {value._type}");
}

return AsStringWithoutTypeCheck(value);
Expand All @@ -50,7 +50,7 @@ public static string AsSymbol(this JsValue value)
{
if (value._type != Types.Symbol)
{
ExceptionHelper.ThrowArgumentException("The value is not a symbol");
ExceptionHelper.ThrowArgumentException($"Expected symbol but got {value._type}");
}

return ((JsSymbol) value)._value;
Expand Down
30 changes: 26 additions & 4 deletions Jint/Native/RegExp/RegExpConstructor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,14 @@ public ObjectInstance Construct(JsValue[] arguments)
try
{
var options = new Scanner("").ParseRegexOptions(f);
r.Value = new Regex(p, options);

var timeout = _engine.Options._RegexTimeoutInterval;
if (timeout.Ticks <= 0)
{
timeout = Regex.InfiniteMatchTimeout;
}

r.Value = new Regex(p, options, timeout);
}
catch (Exception e)
{
Expand All @@ -117,7 +124,7 @@ public ObjectInstance Construct(JsValue[] arguments)
return r;
}

public RegExpInstance Construct(string regExp)
public RegExpInstance Construct(string regExp, Engine engine)
{
var r = new RegExpInstance(Engine);
r.Prototype = PrototypeObject;
Expand All @@ -128,6 +135,12 @@ public RegExpInstance Construct(string regExp)
var flags = (string)scanner.ScanRegExpFlags().Value;
r.Value = scanner.TestRegExp(body, flags);

var timeout = engine.Options._RegexTimeoutInterval;
if (timeout.Ticks > 0)
{
r.Value = new Regex(r.Value.ToString(), r.Value.Options);
}

r.Flags = flags;
AssignFlags(r, flags);
r.Source = System.String.IsNullOrEmpty(body) ? "(?:)" : body;
Expand All @@ -137,7 +150,7 @@ public RegExpInstance Construct(string regExp)
return r;
}

public RegExpInstance Construct(Regex regExp, string flags)
public RegExpInstance Construct(Regex regExp, string flags, Engine engine)
{
var r = new RegExpInstance(Engine);
r.Prototype = PrototypeObject;
Expand All @@ -147,7 +160,16 @@ public RegExpInstance Construct(Regex regExp, string flags)
AssignFlags(r, flags);

r.Source = regExp.ToString();
r.Value = regExp;

var timeout = _engine.Options._RegexTimeoutInterval;
if (timeout.Ticks > 0)
{
r.Value = new Regex(regExp.ToString(), regExp.Options, timeout);
}
else
{
r.Value = regExp;
}

SetRegexProperties(r);

Expand Down
9 changes: 9 additions & 0 deletions Jint/Options.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public sealed class Options
private long _memoryLimit;
private int _maxRecursionDepth = -1;
private TimeSpan _timeoutInterval;
private TimeSpan? _regexTimeoutInterval;
private CultureInfo _culture = CultureInfo.CurrentCulture;
private TimeZoneInfo _localTimeZone = TimeZoneInfo.Local;
private List<Assembly> _lookupAssemblies = new List<Assembly>();
Expand Down Expand Up @@ -145,6 +146,12 @@ public Options TimeoutInterval(TimeSpan timeoutInterval)
return this;
}

public Options RegexTimeoutInterval(TimeSpan regexTimeoutInterval)
{
_regexTimeoutInterval = regexTimeoutInterval;
return this;
}

/// <summary>
/// Sets maximum allowed depth of recursion.
/// </summary>
Expand Down Expand Up @@ -206,6 +213,8 @@ public Options SetReferencesResolver(IReferenceResolver resolver)

internal TimeSpan _TimeoutInterval => _timeoutInterval;

internal TimeSpan _RegexTimeoutInterval => _regexTimeoutInterval ?? _timeoutInterval;

internal CultureInfo _Culture => _culture;

internal TimeZoneInfo _LocalTimeZone => _localTimeZone;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ private JsValue ResolveValue()
var expression = (Literal) _expression;
if (expression.TokenType == TokenType.RegularExpression)
{
return _engine.RegExp.Construct((System.Text.RegularExpressions.Regex) expression.Value, expression.Regex.Flags);
return _engine.RegExp.Construct((System.Text.RegularExpressions.Regex) expression.Value, expression.Regex.Flags, _engine);
}

return JsValue.FromObject(_engine, expression.Value);
Expand Down

0 comments on commit 6e06825

Please sign in to comment.