diff options
author | Jeremy Hylton <jeremy@alum.mit.edu> | 2000-08-31 19:23:01 (GMT) |
---|---|---|
committer | Jeremy Hylton <jeremy@alum.mit.edu> | 2000-08-31 19:23:01 (GMT) |
commit | ee5adfbae6df9a4ae8d73bccc4f3a55b7f382d11 (patch) | |
tree | ecbac10d7a319d2d655ad1ddffcfdb9b75c9c70b | |
parent | c88b99ce060e37a9098708483b7e3c8b5db87fbd (diff) | |
download | cpython-ee5adfbae6df9a4ae8d73bccc4f3a55b7f382d11.zip cpython-ee5adfbae6df9a4ae8d73bccc4f3a55b7f382d11.tar.gz cpython-ee5adfbae6df9a4ae8d73bccc4f3a55b7f382d11.tar.bz2 |
add user-modifiable recursion_limit
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
-rw-r--r-- | Doc/lib/libsys.tex | 18 | ||||
-rw-r--r-- | PC/config.h | 7 | ||||
-rw-r--r-- | Python/ceval.c | 20 | ||||
-rw-r--r-- | Python/sysmodule.c | 54 |
4 files changed, 84 insertions, 15 deletions
diff --git a/Doc/lib/libsys.tex b/Doc/lib/libsys.tex index bbea623..ac28e6f 100644 --- a/Doc/lib/libsys.tex +++ b/Doc/lib/libsys.tex @@ -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'' diff --git a/PC/config.h b/PC/config.h index a09899b..4a57199 100644 --- a/PC/config.h +++ b/PC/config.h @@ -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 diff --git a/Python/ceval.c b/Python/ceval.c index b399b63..7e11250 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -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"); diff --git a/Python/sysmodule.c b/Python/sysmodule.c index d500a36..31d7abf 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -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 |