changeset 10578:cb0883127251

limit on recursion via calls to source function
author John W. Eaton <jwe@octave.org>
date Tue, 27 Apr 2010 12:07:04 -0400
parents 87f879cf48fd
children fd6899b1b00e
files src/ChangeLog src/oct-parse.yy src/ov-usr-fcn.cc src/pt-eval.cc src/pt-eval.h
diffstat 5 files changed, 84 insertions(+), 17 deletions(-) [+]
line wrap: on
line diff
--- a/src/ChangeLog	Tue Apr 27 00:52:28 2010 -0400
+++ b/src/ChangeLog	Tue Apr 27 12:07:04 2010 -0400
@@ -1,3 +1,15 @@
+2010-04-27  John W. Eaton  <jwe@octave.org>
+
+	* ov-usr-fcn.cc (octave_user_script::do_multi_index_op):
+	Correct spelling of max_recursion_depth in error message.
+	(octave_usr_fcn::do_multi_index_op): Ditto.
+	* pt-eval.h, pt-eval.cc (Vmax_recursion_depth): Move definition
+	here from ov-usr-fcn.cc.  Now extern.
+	(Fmax_recursion_depth): Move definition here from ov-usr-fcn.cc.
+	* oct-parse.yy (source_file): Limit recursive calls on a
+	per-file basis.
+	Addresses bug #29491.
+
 2010-04-25  David Bateman  <dbateman@free.fr>
 
 	* oct-parse.yy (octave_function * load_fcn_from_file
--- a/src/oct-parse.yy	Tue Apr 27 00:52:28 2010 -0400
+++ b/src/oct-parse.yy	Tue Apr 27 12:07:04 2010 -0400
@@ -3877,8 +3877,45 @@
 source_file (const std::string& file_name, const std::string& context,
              bool verbose, bool require_file, const std::string& warn_for)
 {
+  // Map from absolute name of script file to recursion level.  We
+  // use a map instead of simply placing a limit on recursion in the
+  // source_file function so that two mutually recursive scripts
+  // written as
+  //
+  //   foo1.m:
+  //   ------
+  //   foo2
+  //
+  //   foo2.m:
+  //   ------
+  //   foo1
+  //
+  // and called with
+  //
+  //   foo1
+  //
+  // (for example) will behave the same if they are written as
+  //
+  //   foo1.m:
+  //   ------
+  //   source ("foo2.m")
+  //
+  //   foo2.m:
+  //   ------
+  //   source ("foo1.m")
+  //
+  // and called with
+  //
+  //   source ("foo1.m")
+  //
+  // (for example).
+
+  static std::map<std::string, int> source_call_depth;
+
   std::string file_full_name = file_ops::tilde_expand (file_name);
 
+  file_full_name = octave_env::make_absolute (file_full_name);
+
   unwind_protect frame;
 
   frame.protect_var (curr_fcn_file_name);
@@ -3887,6 +3924,19 @@
   curr_fcn_file_name = file_name;
   curr_fcn_file_full_name = file_full_name;
 
+  if (source_call_depth.find (file_full_name) == source_call_depth.end ())
+    source_call_depth[file_full_name] = -1;
+
+  frame.protect_var (source_call_depth[file_full_name]);
+
+  source_call_depth[file_full_name]++;
+
+  if (source_call_depth[file_full_name] >= Vmax_recursion_depth)
+    {
+      error ("max_recursion_depth exceeded");
+      return;
+    }
+
   if (! context.empty ())
     {
       if (context == "caller")
--- a/src/ov-usr-fcn.cc	Tue Apr 27 00:52:28 2010 -0400
+++ b/src/ov-usr-fcn.cc	Tue Apr 27 12:07:04 2010 -0400
@@ -49,9 +49,6 @@
 #include "parse.h"
 #include "variables.h"
 
-// Maximum nesting level for functions called recursively.
-static int Vmax_recursion_depth = 256;
-
 // Whether to optimize subsasgn method calls.
 static bool Voptimize_subsasgn_calls = true;
 
@@ -146,7 +143,7 @@
                     octave_call_stack::backtrace_error_message ();
                 }
               else
-                ::error ("max_recursion_limit exceeded");
+                ::error ("max_recursion_depth exceeded");
             }
         }
       else
@@ -339,7 +336,7 @@
 
   if (call_depth >= Vmax_recursion_depth)
     {
-      ::error ("max_recursion_limit exceeded");
+      ::error ("max_recursion_depth exceeded");
       return retval;
     }
 
@@ -668,18 +665,6 @@
   return retval;
 }
 
-DEFUN (max_recursion_depth, args, nargout,
-  "-*- texinfo -*-\n\
-@deftypefn {Built-in Function} {@var{val} =} max_recursion_depth ()\n\
-@deftypefnx {Built-in Function} {@var{old_val} =} max_recursion_depth (@var{new_val})\n\
-Query or set the internal limit on the number of times a function may\n\
-be called recursively.  If the limit is exceeded, an error message is\n\
-printed and control returns to the top level.\n\
-@end deftypefn")
-{
-  return SET_INTERNAL_VARIABLE (max_recursion_depth);
-}
-
 DEFUN (optimize_subsasgn_calls, args, nargout,
   "-*- texinfo -*-\n\
 @deftypefn {Built-in Function} {@var{val} =} optimize_subsasgn_calls ()\n\
--- a/src/pt-eval.cc	Tue Apr 27 00:52:28 2010 -0400
+++ b/src/pt-eval.cc	Tue Apr 27 12:07:04 2010 -0400
@@ -58,6 +58,10 @@
 
 bool tree_evaluator::in_loop_command = false;
 
+// Maximum nesting level for functions, scripts, or sourced files called
+// recursively.
+int Vmax_recursion_depth = 256;
+
 // If TRUE, turn off printing of results in functions (as if a
 // semicolon has been appended to each statement).
 static bool Vsilent_functions = false;
@@ -1168,6 +1172,18 @@
   return ::do_keyboard (args);
 }
 
+DEFUN (max_recursion_depth, args, nargout,
+  "-*- texinfo -*-\n\
+@deftypefn {Built-in Function} {@var{val} =} max_recursion_depth ()\n\
+@deftypefnx {Built-in Function} {@var{old_val} =} max_recursion_depth (@var{new_val})\n\
+Query or set the internal limit on the number of times a function may\n\
+be called recursively.  If the limit is exceeded, an error message is\n\
+printed and control returns to the top level.\n\
+@end deftypefn")
+{
+  return SET_INTERNAL_VARIABLE (max_recursion_depth);
+}
+
 DEFUN (silent_functions, args, nargout,
   "-*- texinfo -*-\n\
 @deftypefn {Built-in Function} {@var{val} =} silent_functions ()\n\
--- a/src/pt-eval.h	Tue Apr 27 00:52:28 2010 -0400
+++ b/src/pt-eval.h	Tue Apr 27 12:07:04 2010 -0400
@@ -175,4 +175,8 @@
 
 extern tree_evaluator *current_evaluator;
 
+// Maximum nesting level for functions, scripts, or sourced files called
+// recursively.
+extern int Vmax_recursion_depth;
+
 #endif