@@ -42,26 +42,62 @@ PyAPI_FUNC(int) PyEval_MergeCompilerFlags(PyCompilerFlags *cf);
4242PyAPI_FUNC (int ) Py_AddPendingCall (int (* func )(void * ), void * arg );
4343PyAPI_FUNC (int ) Py_MakePendingCalls (void );
4444
45- /* Protection against deeply nested recursive calls */
45+ /* Protection against deeply nested recursive calls
46+
47+ In Python 3.0, this protection has two levels:
48+ * normal anti-recursion protection is triggered when the recursion level
49+ exceeds the current recursion limit. It raises a RuntimeError, and sets
50+ the "overflowed" flag in the thread state structure. This flag
51+ temporarily *disables* the normal protection; this allows cleanup code
52+ to potentially outgrow the recursion limit while processing the
53+ RuntimeError.
54+ * "last chance" anti-recursion protection is triggered when the recursion
55+ level exceeds "current recursion limit + 50". By construction, this
56+ protection can only be triggered when the "overflowed" flag is set. It
57+ means the cleanup code has itself gone into an infinite loop, or the
58+ RuntimeError has been mistakingly ignored. When this protection is
59+ triggered, the interpreter aborts with a Fatal Error.
60+
61+ In addition, the "overflowed" flag is automatically reset when the
62+ recursion level drops below "current recursion limit - 50". This heuristic
63+ is meant to ensure that the normal anti-recursion protection doesn't get
64+ disabled too long.
65+
66+ Please note: this scheme has its own limitations. See:
67+ http://mail.python.org/pipermail/python-dev/2008-August/082106.html
68+ for some observations.
69+ */
4670PyAPI_FUNC (void ) Py_SetRecursionLimit (int );
4771PyAPI_FUNC (int ) Py_GetRecursionLimit (void );
4872
49- #define Py_EnterRecursiveCall (where ) \
73+ #define Py_EnterRecursiveCall (where ) \
5074 (_Py_MakeRecCheck(PyThreadState_GET()->recursion_depth) && \
5175 _Py_CheckRecursiveCall(where))
5276#define Py_LeaveRecursiveCall () \
53- do{ if((--PyThreadState_GET()->recursion_depth) < \
54- _Py_CheckRecursionLimit - 50) \
55- PyThreadState_GET()->overflowed = 0; \
56- } while(0)
77+ do{ if(_Py_MakeEndRecCheck(PyThreadState_GET()->recursion_depth)) \
78+ PyThreadState_GET()->overflowed = 0; \
79+ } while(0)
5780PyAPI_FUNC (int ) _Py_CheckRecursiveCall (char * where );
5881PyAPI_DATA (int ) _Py_CheckRecursionLimit ;
82+
5983#ifdef USE_STACKCHECK
60- # define _Py_MakeRecCheck (x ) (++(x) > --_Py_CheckRecursionLimit)
84+ /* With USE_STACKCHECK, we artificially decrement the recursion limit in order
85+ to trigger regular stack checks in _Py_CheckRecursiveCall(), except if
86+ the "overflowed" flag is set, in which case we need the true value
87+ of _Py_CheckRecursionLimit for _Py_MakeEndRecCheck() to function properly.
88+ */
89+ # define _Py_MakeRecCheck (x ) \
90+ (++(x) > (_Py_CheckRecursionLimit += PyThreadState_GET()->overflowed - 1))
6191#else
6292# define _Py_MakeRecCheck (x ) (++(x) > _Py_CheckRecursionLimit)
6393#endif
6494
95+ #ifdef USE_STACKCHECK
96+ # define _Py_MakeEndRecCheck (x ) (--(x) < _Py_CheckRecursionLimit - 50)
97+ #else
98+ # define _Py_MakeEndRecCheck (x ) (--(x) < _Py_CheckRecursionLimit - 50)
99+ #endif
100+
65101#define Py_ALLOW_RECURSION \
66102 do { unsigned char _old = PyThreadState_GET()->recursion_critical;\
67103 PyThreadState_GET()->recursion_critical = 1;
0 commit comments