Browse Source

Replace DiscardRecursion with option to set MaxRecursionDepth negative

auz34 11 years ago
parent
commit
42c5fe631b
3 changed files with 38 additions and 36 deletions
  1. 4 4
      Jint.Tests/Runtime/EngineTests.cs
  2. 12 18
      Jint/Options.cs
  3. 22 14
      Jint/Runtime/ExpressionIntepreter.cs

+ 4 - 4
Jint.Tests/Runtime/EngineTests.cs

@@ -627,7 +627,7 @@ namespace Jint.Tests.Runtime
             ";
 
             Assert.Throws<RecursionDiscardedException>(
-                () => new Engine(cfg => cfg.DiscardRecursion()).Execute(script)
+                () => new Engine(cfg => cfg.MaxRecursionDepth(0)).Execute(script)
             );
         }
 
@@ -646,7 +646,7 @@ namespace Jint.Tests.Runtime
             ";
 
             Assert.Throws<RecursionDiscardedException>(
-                () => new Engine(cfg => cfg.DiscardRecursion()).Execute(script)
+                () => new Engine(cfg => cfg.MaxRecursionDepth(0)).Execute(script)
             );
         }
 
@@ -679,7 +679,7 @@ namespace Jint.Tests.Runtime
             ";
 
             Assert.Throws<RecursionDiscardedException>(
-                () => new Engine(cfg => cfg.DiscardRecursion()).Execute(script)
+                () => new Engine(cfg => cfg.MaxRecursionDepth(0)).Execute(script)
             );
         }
 
@@ -715,7 +715,7 @@ namespace Jint.Tests.Runtime
 
             try
             {
-                new Engine(cfg => cfg.DiscardRecursion()).Execute(script);
+                new Engine(cfg => cfg.MaxRecursionDepth(0)).Execute(script);
             }
             catch (RecursionDiscardedException ex)
             {

+ 12 - 18
Jint/Options.cs

@@ -11,13 +11,12 @@ namespace Jint
     public class Options
     {
         private bool _discardGlobal;
-        private bool _discardRecursion;
         private bool _strict;
         private bool _allowDebuggerStatement;
         private bool _allowClr;
         private readonly List<IObjectConverter> _objectConverters = new List<IObjectConverter>();
         private int _maxStatements;
-        private int _maxRecursionDepth;
+        private int _maxRecursionDepth = -1; 
         private TimeSpan _timeoutInterval;
         private CultureInfo _culture = CultureInfo.CurrentCulture;
         private TimeZoneInfo _localTimeZone = TimeZoneInfo.Local;
@@ -33,16 +32,6 @@ namespace Jint
             return this;
         }
 
-        /// <summary>
-        /// When called, doesn't allow to use recursion.
-        /// Can be useful when you can not trust to author of the script and safety has higher priority. 
-        /// </summary>
-        public Options DiscardRecursion(bool discard = true)
-        {
-            _discardRecursion = discard;
-            return this;
-        }
-
         /// <summary>
         /// Run the script in strict mode.
         /// </summary>
@@ -97,7 +86,17 @@ namespace Jint
             return this;
         }
 
-        public Options MaxRecursionDepth(int maxRecursionDepth = 0)
+        /// <summary>
+        /// Sets maximum allowed depth of recursion.
+        /// </summary>
+        /// <param name="maxRecursionDepth">
+        /// The allowed depth.
+        /// a) In case max depth is negative engine ignores stack overflow protection logic;
+        /// b) In case max depth is zero no recursion is allowed.
+        /// c) In case max depth is equal to n it means that in one scope function can be called no more than n times.
+        /// </param>
+        /// <returns>Options instance for fluent syntax</returns>
+        public Options MaxRecursionDepth(int maxRecursionDepth = -1)
         {
             _maxRecursionDepth = maxRecursionDepth;
             return this;
@@ -155,11 +154,6 @@ namespace Jint
             return _maxRecursionDepth;
         }
 
-        internal bool IsRecursionAllowed()
-        {
-            return !_discardRecursion;
-        }
-
         internal TimeSpan GetTimeoutInterval()
         {
             return _timeoutInterval;

+ 22 - 14
Jint/Runtime/ExpressionIntepreter.cs

@@ -797,25 +797,30 @@ namespace Jint.Runtime
             var func = _engine.GetValue(callee);
             
             var r = callee as Reference;
-            var stackItem = new Tuple<CallExpression, JsValue, string>(callExpression, func, r != null ? r.GetReferencedName() : "anonymous function");
 
-            var recursionDepth = _engine.CallStack.Count(ce => ce.Item1 == callExpression || ce.Item2 == func);
-
-            if (recursionDepth > 0)
+            var isRecursionHandled = _engine.Options.GetMaxRecursionDepth() >= 0;
+            if (isRecursionHandled)
             {
-                if (!_engine.Options.IsRecursionAllowed())
-                {
-                    throw new RecursionDiscardedException(_engine.CallStack, stackItem);
-                }
+                var stackItem = new Tuple<CallExpression, JsValue, string>(callExpression, func, r != null ? r.GetReferencedName() : "anonymous function");
+
+                var recursionDepth = _engine.CallStack.Count(ce => ce.Item1 == callExpression || ce.Item2 == func);
 
-                if (_engine.Options.GetMaxRecursionDepth() != 0
-                    && recursionDepth > _engine.Options.GetMaxRecursionDepth())
+                if (recursionDepth > 0)
                 {
-                    throw new RecursionDepthOverflowException(_engine.CallStack, stackItem);
+                    if (_engine.Options.GetMaxRecursionDepth() == 0)
+                    {
+                        throw new RecursionDiscardedException(_engine.CallStack, stackItem);
+                    }
+
+                    if (_engine.Options.GetMaxRecursionDepth() != 0
+                        && recursionDepth > _engine.Options.GetMaxRecursionDepth())
+                    {
+                        throw new RecursionDepthOverflowException(_engine.CallStack, stackItem);
+                    }
                 }
-            }
 
-            _engine.CallStack.Push(stackItem);
+                _engine.CallStack.Push(stackItem);
+            }
 
             if (func == Undefined.Instance)
             {
@@ -858,7 +863,10 @@ namespace Jint.Runtime
             
             var result = callable.Call(thisObject, arguments);
 
-            _engine.CallStack.Pop();
+            if (isRecursionHandled)
+            {
+                _engine.CallStack.Pop();
+            }
 
             return result;
         }