]> granicus.if.org Git - python/commitdiff
add user-modifiable recursion_limit
authorJeremy Hylton <jeremy@alum.mit.edu>
Thu, 31 Aug 2000 19:23:01 +0000 (19:23 +0000)
committerJeremy Hylton <jeremy@alum.mit.edu>
Thu, 31 Aug 2000 19:23:01 +0000 (19:23 +0000)
ceval.c:
    define recurion_limit (static), default value is 2500
    define Py_GetRecursionLimit and Py_SetRecursionLimit
    raise RuntimeError if limit is exceeded
PC/config.h:
    remove plat-specific definition
sysmodule.c:
    add sys.(get|set)recursionlimit

Doc/lib/libsys.tex
PC/config.h
Python/ceval.c
Python/sysmodule.c

index bbea623a57ba175353b895dfe406d6c6abf4b839..ac28e6f975b4dca82c70eb7dfe4a844c7612f930 100644 (file)
@@ -148,6 +148,13 @@ generally one higher than you might expect, because it includes the
 (temporary) reference as an argument to \function{getrefcount()}.
 \end{funcdesc}
 
+\begin{funcdesc}{getrecursionlimit}{}
+Return the current value of the recursion limit, the maximum depth of
+the Python interpreter stack.  This limit prevents infinite recursion
+from causing an overflow of the C stack and crashing Python.  It can
+be set by \function{setrecursionlimit}.
+\end{funcdesc}
+
 \begin{datadesc}{hexversion}
 The version number encoded as a single integer.  This is guaranteed to
 increase with each version, including proper support for
@@ -275,6 +282,17 @@ maximizing responsiveness as well as overhead.
 \index{profile function}
 \index{profiler}
 
+\begin{funcdesc}{setrecursionlimit}{limit}
+Set the maximum depth of the Python interpreter stack to \var{limit}.
+This limit prevents infinite recursion from causing an overflow of the
+C stack and crashing Python.  
+
+The highest possible limit is platform-dependent.  A user may need to
+set the limit higher when she has a program that requires deep
+recursion and a platform that supports a higher limit.  This should be
+done with care, because a too-high limit can lead to a crash.
+\edn{funcdesc}
+
 \begin{funcdesc}{settrace}{tracefunc}
   Set the system's trace function, which allows you to implement a
   Python source code debugger in Python.  See section ``How It Works''
index a09899b9436233f3768eba0b4ee90c1cc7167025..4a57199fdc37b65baeb37aef560ce6a68ca97f94 100644 (file)
@@ -443,13 +443,6 @@ typedef unsigned long uintptr_t;
 #define SIZEOF_LONG 4
 #define SIZEOF_LONG_LONG 8
 
-/* Smaller stack size limit.  (9500 would work too, but we're conservative.) */
-
-#ifndef MAX_RECURSION_DEPTH
-#define MAX_RECURSION_DEPTH 5000
-#endif
-
-
 /* EXPERIMENTAL FEATURE: When CHECK_IMPORT_CASE is defined, check case of
    imported modules against case of file; this causes "import String" to fail
    with a NameError exception when it finds "string.py".  Normally, you set
index b399b638ea6ed853eb43da65c5ce044f4a9d9503..7e11250447e10677e81ba9b2c8bab3c55d104e10 100644 (file)
@@ -298,6 +298,20 @@ Py_MakePendingCalls(void)
 }
 
 
+/* The interpreter's recursion limit */
+
+static int recursion_limit = 2500;
+
+int Py_GetRecursionLimit(void)
+{
+       return recursion_limit;
+}
+
+void Py_SetRecursionLimit(int new_limit)
+{
+       recursion_limit = new_limit;
+}
+
 /* Status code for main loop (reason for stack unwind) */
 
 enum why_code {
@@ -326,10 +340,6 @@ PyEval_EvalCode(PyCodeObject *co, PyObject *globals, PyObject *locals)
 
 /* Interpreter main loop */
 
-#ifndef MAX_RECURSION_DEPTH
-#define MAX_RECURSION_DEPTH 10000
-#endif
-
 static PyObject *
 eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
           PyObject **args, int argcount, PyObject **kws, int kwcount,
@@ -565,7 +575,7 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
                }
        }
 
-       if (++tstate->recursion_depth > MAX_RECURSION_DEPTH) {
+       if (++tstate->recursion_depth > recursion_limit) {
                --tstate->recursion_depth;
                PyErr_SetString(PyExc_RuntimeError,
                                "Maximum recursion depth exceeded");
index d500a364719867f5c35f3007c42fc9c59ec8ab98..31d7abf27682d04ea1d9d4e7a66520363d90c3b9 100644 (file)
@@ -199,6 +199,45 @@ static char setcheckinterval_doc[] =
 Tell the Python interpreter to check for asynchronous events every\n\
 n instructions.  This also affects how often thread switches occur.";
 
+static PyObject *
+sys_setrecursionlimit(PyObject *self, PyObject *args)
+{
+       int new_limit;
+       if (!PyArg_ParseTuple(args, "i:setrecursionlimit", &new_limit))
+               return NULL;
+       if (new_limit <= 0) {
+               PyErr_SetString(PyExc_ValueError, 
+                               "recursion limit must be positive");  
+               return NULL;
+       }
+       Py_SetRecursionLimit(new_limit);
+       Py_INCREF(Py_None);
+       return Py_None;
+}
+
+static char setrecursionlimit_doc[] =
+"setrecursionlimit(n)\n\
+\n\
+Set the maximum depth of the Python interpreter stack to n.  This\n\
+limit prevents infinite recursion from causing an overflow of the C\n\
+stack and crashing Python.  The highest possible limit is platform-\n\
+dependent.";
+
+static PyObject *
+sys_getrecursionlimit(PyObject *self, PyObject *args)
+{
+       if (!PyArg_ParseTuple(args, ":getrecursionlimit"))
+               return NULL;
+       return PyInt_FromLong(Py_GetRecursionLimit());
+}
+
+static char getrecursionlimit_doc[] =
+"getrecursionlimit()\n\
+\n\
+Return the current value of the recursion limit, the maximum depth\n\
+of the Python interpreter stack.  This limit prevents infinite\n\
+recursion from causing an overflow of the C stack and crashing Python.";
+
 #ifdef USE_MALLOPT
 /* Link with -lmalloc (or -lmpc) on an SGI */
 #include <malloc.h>
@@ -268,7 +307,8 @@ static PyMethodDef sys_methods[] = {
        /* Might as well keep this in alphabetic order */
        {"exc_info",    sys_exc_info, 1, exc_info_doc},
        {"exit",        sys_exit, 0, exit_doc},
-       {"getdefaultencoding", sys_getdefaultencoding, 1, getdefaultencoding_doc},
+       {"getdefaultencoding", sys_getdefaultencoding, 1,
+        getdefaultencoding_doc}, 
 #ifdef COUNT_ALLOCS
        {"getcounts",   sys_getcounts, 1},
 #endif
@@ -280,12 +320,18 @@ static PyMethodDef sys_methods[] = {
        {"gettotalrefcount", sys_gettotalrefcount, 1},
 #endif
        {"getrefcount", sys_getrefcount, 1, getrefcount_doc},
+       {"getrecursionlimit", sys_getrecursionlimit, 1,
+        getrecursionlimit_doc},
 #ifdef USE_MALLOPT
        {"mdebug",      sys_mdebug, 1},
 #endif
-       {"setdefaultencoding", sys_setdefaultencoding, 1, setdefaultencoding_doc},
-       {"setcheckinterval",    sys_setcheckinterval, 1, setcheckinterval_doc},
+       {"setdefaultencoding", sys_setdefaultencoding, 1,
+        setdefaultencoding_doc}, 
+       {"setcheckinterval",    sys_setcheckinterval, 1,
+        setcheckinterval_doc}, 
        {"setprofile",  sys_setprofile, 0, setprofile_doc},
+       {"setrecursionlimit", sys_setrecursionlimit, 1,
+        setrecursionlimit_doc},
        {"settrace",    sys_settrace, 0, settrace_doc},
        {NULL,          NULL}           /* sentinel */
 };
@@ -376,8 +422,10 @@ Functions:\n\
 exc_info() -- return thread-safe information about the current exception\n\
 exit() -- exit the interpreter by raising SystemExit\n\
 getrefcount() -- return the reference count for an object (plus one :-)\n\
+getrecursionlimit() -- return the max recursion depth for the interpreter\n\
 setcheckinterval() -- control how often the interpreter checks for events\n\
 setprofile() -- set the global profiling function\n\
+setrecursionlimit() -- set the max recursion depth for the interpreter\n\
 settrace() -- set the global debug tracing function\n\
 "
 #endif