From be434dc0380d9f5c7c800de9943cc46d55fd9491 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 5 Nov 2019 00:51:22 +0100 Subject: [PATCH] bpo-38644: Pass tstate to Py_EnterRecursiveCall() (GH-16997) * Add _Py_EnterRecursiveCall() and _Py_LeaveRecursiveCall() which require a tstate argument. * Pass tstate to _Py_MakeRecCheck() and _Py_CheckRecursiveCall(). * Convert Py_EnterRecursiveCall() and Py_LeaveRecursiveCall() macros to static inline functions. _PyThreadState_GET() is the most efficient way to get the tstate, and so using it with _Py_EnterRecursiveCall() and _Py_LeaveRecursiveCall() should be a little bit more efficient than using Py_EnterRecursiveCall() and Py_LeaveRecursiveCall() which use the "slower" PyThreadState_GET(). --- Include/cpython/ceval.h | 45 +++++++++++++++-------- Objects/abstract.c | 80 +++++++++++++++++++++++++---------------- Objects/call.c | 44 ++++++++++++----------- Objects/descrobject.c | 34 ++++++++++-------- Objects/methodobject.c | 50 ++++++++++++++------------ Objects/object.c | 70 +++++++++++++++++++++--------------- Python/ceval.c | 14 ++++---- 7 files changed, 201 insertions(+), 136 deletions(-) diff --git a/Include/cpython/ceval.h b/Include/cpython/ceval.h index 61bbc4f69d5..1e2c4577a78 100644 --- a/Include/cpython/ceval.h +++ b/Include/cpython/ceval.h @@ -11,20 +11,31 @@ PyAPI_DATA(int) _Py_CheckRecursionLimit; #ifdef USE_STACKCHECK /* With USE_STACKCHECK macro defined, trigger stack checks in _Py_CheckRecursiveCall() on every 64th call to Py_EnterRecursiveCall. */ -# define _Py_MakeRecCheck(x) \ - (++(x) > _Py_CheckRecursionLimit || \ - ++(PyThreadState_GET()->stackcheck_counter) > 64) +static inline int _Py_MakeRecCheck(PyThreadState *tstate) { + return (++tstate->recursion_depth > _Py_CheckRecursionLimit + || ++tstate->stackcheck_counter > 64); +} #else -# define _Py_MakeRecCheck(x) (++(x) > _Py_CheckRecursionLimit) +static inline int _Py_MakeRecCheck(PyThreadState *tstate) { + return (++tstate->recursion_depth > _Py_CheckRecursionLimit); +} #endif -PyAPI_FUNC(int) _Py_CheckRecursiveCall(const char *where); +PyAPI_FUNC(int) _Py_CheckRecursiveCall( + PyThreadState *tstate, + const char *where); -#define _Py_EnterRecursiveCall_macro(where) \ - (_Py_MakeRecCheck(PyThreadState_GET()->recursion_depth) && \ - _Py_CheckRecursiveCall(where)) +static inline int _Py_EnterRecursiveCall(PyThreadState *tstate, + const char *where) { + return (_Py_MakeRecCheck(tstate) && _Py_CheckRecursiveCall(tstate, where)); +} -#define Py_EnterRecursiveCall(where) _Py_EnterRecursiveCall_macro(where) +static inline int _Py_EnterRecursiveCall_inline(const char *where) { + PyThreadState *tstate = PyThreadState_GET(); + return _Py_EnterRecursiveCall(tstate, where); +} + +#define Py_EnterRecursiveCall(where) _Py_EnterRecursiveCall_inline(where) /* Compute the "lower-water mark" for a recursion limit. When @@ -38,12 +49,18 @@ PyAPI_FUNC(int) _Py_CheckRecursiveCall(const char *where); #define _Py_MakeEndRecCheck(x) \ (--(x) < _Py_RecursionLimitLowerWaterMark(_Py_CheckRecursionLimit)) -#define _Py_LeaveRecursiveCall_macro() \ - do{ if(_Py_MakeEndRecCheck(PyThreadState_GET()->recursion_depth)) \ - PyThreadState_GET()->overflowed = 0; \ - } while(0) +static inline void _Py_LeaveRecursiveCall(PyThreadState *tstate) { + if (_Py_MakeEndRecCheck(tstate->recursion_depth)) { + tstate->overflowed = 0; + } +} -#define Py_LeaveRecursiveCall() _Py_LeaveRecursiveCall_macro() +static inline void _Py_LeaveRecursiveCall_inline(void) { + PyThreadState *tstate = PyThreadState_GET(); + _Py_LeaveRecursiveCall(tstate); +} + +#define Py_LeaveRecursiveCall() _Py_LeaveRecursiveCall_inline() #ifdef __cplusplus } diff --git a/Objects/abstract.c b/Objects/abstract.c index 3db56fab2c8..dc8ba10762d 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -1,6 +1,7 @@ /* Abstract Object Interface (many thanks to Jim Fulton) */ #include "Python.h" +#include "pycore_pyerrors.h" #include "pycore_pystate.h" #include #include "structmember.h" /* we need the offsetof() macro from there */ @@ -2459,8 +2460,8 @@ recursive_isinstance(PyObject *inst, PyObject *cls) return retval; } -int -PyObject_IsInstance(PyObject *inst, PyObject *cls) +static int +object_isinstance(PyThreadState *tstate, PyObject *inst, PyObject *cls) { _Py_IDENTIFIER(__instancecheck__); PyObject *checker; @@ -2475,34 +2476,31 @@ PyObject_IsInstance(PyObject *inst, PyObject *cls) } if (PyTuple_Check(cls)) { - Py_ssize_t i; - Py_ssize_t n; - int r = 0; - - if (Py_EnterRecursiveCall(" in __instancecheck__")) + if (_Py_EnterRecursiveCall(tstate, " in __instancecheck__")) { return -1; - n = PyTuple_GET_SIZE(cls); - for (i = 0; i < n; ++i) { + } + Py_ssize_t n = PyTuple_GET_SIZE(cls); + int r = 0; + for (Py_ssize_t i = 0; i < n; ++i) { PyObject *item = PyTuple_GET_ITEM(cls, i); - r = PyObject_IsInstance(inst, item); + r = object_isinstance(tstate, inst, item); if (r != 0) /* either found it, or got an error */ break; } - Py_LeaveRecursiveCall(); + _Py_LeaveRecursiveCall(tstate); return r; } checker = _PyObject_LookupSpecial(cls, &PyId___instancecheck__); if (checker != NULL) { - PyObject *res; int ok = -1; - if (Py_EnterRecursiveCall(" in __instancecheck__")) { + if (_Py_EnterRecursiveCall(tstate, " in __instancecheck__")) { Py_DECREF(checker); return ok; } - res = _PyObject_CallOneArg(checker, inst); - Py_LeaveRecursiveCall(); + PyObject *res = _PyObject_CallOneArg(checker, inst); + _Py_LeaveRecursiveCall(tstate); Py_DECREF(checker); if (res != NULL) { ok = PyObject_IsTrue(res); @@ -2510,12 +2508,23 @@ PyObject_IsInstance(PyObject *inst, PyObject *cls) } return ok; } - else if (PyErr_Occurred()) + else if (_PyErr_Occurred(tstate)) { return -1; + } + /* Probably never reached anymore. */ return recursive_isinstance(inst, cls); } + +int +PyObject_IsInstance(PyObject *inst, PyObject *cls) +{ + PyThreadState *tstate = _PyThreadState_GET(); + return object_isinstance(tstate, inst, cls); +} + + static int recursive_issubclass(PyObject *derived, PyObject *cls) { @@ -2534,8 +2543,8 @@ recursive_issubclass(PyObject *derived, PyObject *cls) return abstract_issubclass(derived, cls); } -int -PyObject_IsSubclass(PyObject *derived, PyObject *cls) +static int +object_issubclass(PyThreadState *tstate, PyObject *derived, PyObject *cls) { _Py_IDENTIFIER(__subclasscheck__); PyObject *checker; @@ -2549,34 +2558,32 @@ PyObject_IsSubclass(PyObject *derived, PyObject *cls) } if (PyTuple_Check(cls)) { - Py_ssize_t i; - Py_ssize_t n; - int r = 0; - if (Py_EnterRecursiveCall(" in __subclasscheck__")) + if (_Py_EnterRecursiveCall(tstate, " in __subclasscheck__")) { return -1; - n = PyTuple_GET_SIZE(cls); - for (i = 0; i < n; ++i) { + } + Py_ssize_t n = PyTuple_GET_SIZE(cls); + int r = 0; + for (Py_ssize_t i = 0; i < n; ++i) { PyObject *item = PyTuple_GET_ITEM(cls, i); - r = PyObject_IsSubclass(derived, item); + r = object_issubclass(tstate, derived, item); if (r != 0) /* either found it, or got an error */ break; } - Py_LeaveRecursiveCall(); + _Py_LeaveRecursiveCall(tstate); return r; } checker = _PyObject_LookupSpecial(cls, &PyId___subclasscheck__); if (checker != NULL) { - PyObject *res; int ok = -1; - if (Py_EnterRecursiveCall(" in __subclasscheck__")) { + if (_Py_EnterRecursiveCall(tstate, " in __subclasscheck__")) { Py_DECREF(checker); return ok; } - res = _PyObject_CallOneArg(checker, derived); - Py_LeaveRecursiveCall(); + PyObject *res = _PyObject_CallOneArg(checker, derived); + _Py_LeaveRecursiveCall(tstate); Py_DECREF(checker); if (res != NULL) { ok = PyObject_IsTrue(res); @@ -2584,12 +2591,23 @@ PyObject_IsSubclass(PyObject *derived, PyObject *cls) } return ok; } - else if (PyErr_Occurred()) + else if (_PyErr_Occurred(tstate)) { return -1; + } + /* Probably never reached anymore. */ return recursive_issubclass(derived, cls); } + +int +PyObject_IsSubclass(PyObject *derived, PyObject *cls) +{ + PyThreadState *tstate = _PyThreadState_GET(); + return object_issubclass(tstate, derived, cls); +} + + int _PyObject_RealIsInstance(PyObject *inst, PyObject *cls) { diff --git a/Objects/call.c b/Objects/call.c index a715bcbee4a..b7588b302fb 100644 --- a/Objects/call.c +++ b/Objects/call.c @@ -1,5 +1,6 @@ #include "Python.h" #include "pycore_object.h" +#include "pycore_pyerrors.h" #include "pycore_pystate.h" #include "pycore_tupleobject.h" #include "frameobject.h" @@ -126,12 +127,15 @@ _PyObject_FastCallDict(PyObject *callable, PyObject *const *args, PyObject * _PyObject_MakeTpCall(PyObject *callable, PyObject *const *args, Py_ssize_t nargs, PyObject *keywords) { + PyThreadState *tstate = _PyThreadState_GET(); + /* Slow path: build a temporary tuple for positional arguments and a * temporary dictionary for keyword arguments (if any) */ ternaryfunc call = Py_TYPE(callable)->tp_call; if (call == NULL) { - PyErr_Format(PyExc_TypeError, "'%.200s' object is not callable", - Py_TYPE(callable)->tp_name); + _PyErr_Format(tstate, PyExc_TypeError, + "'%.200s' object is not callable", + Py_TYPE(callable)->tp_name); return NULL; } @@ -162,10 +166,10 @@ _PyObject_MakeTpCall(PyObject *callable, PyObject *const *args, Py_ssize_t nargs } PyObject *result = NULL; - if (Py_EnterRecursiveCall(" while calling a Python object") == 0) + if (_Py_EnterRecursiveCall(tstate, " while calling a Python object") == 0) { result = call(callable, argstuple, kwdict); - Py_LeaveRecursiveCall(); + _Py_LeaveRecursiveCall(tstate); } Py_DECREF(argstuple); @@ -220,13 +224,14 @@ PyVectorcall_Call(PyObject *callable, PyObject *tuple, PyObject *kwargs) PyObject * PyObject_Call(PyObject *callable, PyObject *args, PyObject *kwargs) { + PyThreadState *tstate = _PyThreadState_GET(); ternaryfunc call; PyObject *result; /* PyObject_Call() must not be called with an exception set, because it can clear it (directly or indirectly) and so the caller loses its exception */ - assert(!PyErr_Occurred()); + assert(!_PyErr_Occurred(tstate)); assert(PyTuple_Check(args)); assert(kwargs == NULL || PyDict_Check(kwargs)); @@ -236,17 +241,19 @@ PyObject_Call(PyObject *callable, PyObject *args, PyObject *kwargs) else { call = callable->ob_type->tp_call; if (call == NULL) { - PyErr_Format(PyExc_TypeError, "'%.200s' object is not callable", - callable->ob_type->tp_name); + _PyErr_Format(tstate, PyExc_TypeError, + "'%.200s' object is not callable", + callable->ob_type->tp_name); return NULL; } - if (Py_EnterRecursiveCall(" while calling a Python object")) + if (_Py_EnterRecursiveCall(tstate, " while calling a Python object")) { return NULL; + } result = (*call)(callable, args, kwargs); - Py_LeaveRecursiveCall(); + _Py_LeaveRecursiveCall(tstate); return _Py_CheckFunctionResult(callable, result, NULL); } @@ -266,30 +273,27 @@ static PyObject* _Py_HOT_FUNCTION function_code_fastcall(PyCodeObject *co, PyObject *const *args, Py_ssize_t nargs, PyObject *globals) { - PyFrameObject *f; - PyThreadState *tstate = _PyThreadState_GET(); - PyObject **fastlocals; - Py_ssize_t i; - PyObject *result; - assert(globals != NULL); + + PyThreadState *tstate = _PyThreadState_GET(); + assert(tstate != NULL); + /* XXX Perhaps we should create a specialized _PyFrame_New_NoTrack() that doesn't take locals, but does take builtins without sanity checking them. */ - assert(tstate != NULL); - f = _PyFrame_New_NoTrack(tstate, co, globals, NULL); + PyFrameObject *f = _PyFrame_New_NoTrack(tstate, co, globals, NULL); if (f == NULL) { return NULL; } - fastlocals = f->f_localsplus; + PyObject **fastlocals = f->f_localsplus; - for (i = 0; i < nargs; i++) { + for (Py_ssize_t i = 0; i < nargs; i++) { Py_INCREF(*args); fastlocals[i] = *args++; } - result = PyEval_EvalFrameEx(f,0); + PyObject *result = PyEval_EvalFrameEx(f, 0); if (Py_REFCNT(f) > 1) { Py_DECREF(f); diff --git a/Objects/descrobject.c b/Objects/descrobject.c index c50fe00ce80..dbab4cd4da2 100644 --- a/Objects/descrobject.c +++ b/Objects/descrobject.c @@ -271,9 +271,9 @@ method_check_args(PyObject *func, PyObject *const *args, Py_ssize_t nargs, PyObj } static inline funcptr -method_enter_call(PyObject *func) +method_enter_call(PyThreadState *tstate, PyObject *func) { - if (Py_EnterRecursiveCall(" while calling a Python object")) { + if (_Py_EnterRecursiveCall(tstate, " while calling a Python object")) { return NULL; } return (funcptr)((PyMethodDescrObject *)func)->d_method->ml_meth; @@ -284,6 +284,7 @@ static PyObject * method_vectorcall_VARARGS( PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) { + PyThreadState *tstate = _PyThreadState_GET(); Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); if (method_check_args(func, args, nargs, kwnames)) { return NULL; @@ -292,14 +293,14 @@ method_vectorcall_VARARGS( if (argstuple == NULL) { return NULL; } - PyCFunction meth = (PyCFunction)method_enter_call(func); + PyCFunction meth = (PyCFunction)method_enter_call(tstate, func); if (meth == NULL) { Py_DECREF(argstuple); return NULL; } PyObject *result = meth(args[0], argstuple); Py_DECREF(argstuple); - Py_LeaveRecursiveCall(); + _Py_LeaveRecursiveCall(tstate); return result; } @@ -307,6 +308,7 @@ static PyObject * method_vectorcall_VARARGS_KEYWORDS( PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) { + PyThreadState *tstate = _PyThreadState_GET(); Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); if (method_check_args(func, args, nargs, NULL)) { return NULL; @@ -325,12 +327,12 @@ method_vectorcall_VARARGS_KEYWORDS( } } PyCFunctionWithKeywords meth = (PyCFunctionWithKeywords) - method_enter_call(func); + method_enter_call(tstate, func); if (meth == NULL) { goto exit; } result = meth(args[0], argstuple, kwdict); - Py_LeaveRecursiveCall(); + _Py_LeaveRecursiveCall(tstate); exit: Py_DECREF(argstuple); Py_XDECREF(kwdict); @@ -341,17 +343,18 @@ static PyObject * method_vectorcall_FASTCALL( PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) { + PyThreadState *tstate = _PyThreadState_GET(); Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); if (method_check_args(func, args, nargs, kwnames)) { return NULL; } _PyCFunctionFast meth = (_PyCFunctionFast) - method_enter_call(func); + method_enter_call(tstate, func); if (meth == NULL) { return NULL; } PyObject *result = meth(args[0], args+1, nargs-1); - Py_LeaveRecursiveCall(); + _Py_LeaveRecursiveCall(tstate); return result; } @@ -359,17 +362,18 @@ static PyObject * method_vectorcall_FASTCALL_KEYWORDS( PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) { + PyThreadState *tstate = _PyThreadState_GET(); Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); if (method_check_args(func, args, nargs, NULL)) { return NULL; } _PyCFunctionFastWithKeywords meth = (_PyCFunctionFastWithKeywords) - method_enter_call(func); + method_enter_call(tstate, func); if (meth == NULL) { return NULL; } PyObject *result = meth(args[0], args+1, nargs-1, kwnames); - Py_LeaveRecursiveCall(); + _Py_LeaveRecursiveCall(tstate); return result; } @@ -377,6 +381,7 @@ static PyObject * method_vectorcall_NOARGS( PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) { + PyThreadState *tstate = _PyThreadState_GET(); Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); if (method_check_args(func, args, nargs, kwnames)) { return NULL; @@ -386,12 +391,12 @@ method_vectorcall_NOARGS( "%.200s() takes no arguments (%zd given)", get_name(func), nargs-1); return NULL; } - PyCFunction meth = (PyCFunction)method_enter_call(func); + PyCFunction meth = (PyCFunction)method_enter_call(tstate, func); if (meth == NULL) { return NULL; } PyObject *result = meth(args[0], NULL); - Py_LeaveRecursiveCall(); + _Py_LeaveRecursiveCall(tstate); return result; } @@ -399,6 +404,7 @@ static PyObject * method_vectorcall_O( PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) { + PyThreadState *tstate = _PyThreadState_GET(); Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); if (method_check_args(func, args, nargs, kwnames)) { return NULL; @@ -409,12 +415,12 @@ method_vectorcall_O( get_name(func), nargs-1); return NULL; } - PyCFunction meth = (PyCFunction)method_enter_call(func); + PyCFunction meth = (PyCFunction)method_enter_call(tstate, func); if (meth == NULL) { return NULL; } PyObject *result = meth(args[0], args[1]); - Py_LeaveRecursiveCall(); + _Py_LeaveRecursiveCall(tstate); return result; } diff --git a/Objects/methodobject.c b/Objects/methodobject.c index a5f0c5d3465..3ce15604b90 100644 --- a/Objects/methodobject.c +++ b/Objects/methodobject.c @@ -3,6 +3,7 @@ #include "Python.h" #include "pycore_object.h" +#include "pycore_pyerrors.h" #include "pycore_pymem.h" #include "pycore_pystate.h" #include "structmember.h" @@ -344,22 +345,22 @@ get_name(PyObject *func) typedef void (*funcptr)(void); static inline int -cfunction_check_kwargs(PyObject *func, PyObject *kwnames) +cfunction_check_kwargs(PyThreadState *tstate, PyObject *func, PyObject *kwnames) { - assert(!PyErr_Occurred()); + assert(!_PyErr_Occurred(tstate)); assert(PyCFunction_Check(func)); if (kwnames && PyTuple_GET_SIZE(kwnames)) { - PyErr_Format(PyExc_TypeError, - "%.200s() takes no keyword arguments", get_name(func)); + _PyErr_Format(tstate, PyExc_TypeError, + "%.200s() takes no keyword arguments", get_name(func)); return -1; } return 0; } static inline funcptr -cfunction_enter_call(PyObject *func) +cfunction_enter_call(PyThreadState *tstate, PyObject *func) { - if (Py_EnterRecursiveCall(" while calling a Python object")) { + if (_Py_EnterRecursiveCall(tstate, " while calling a Python object")) { return NULL; } return (funcptr)PyCFunction_GET_FUNCTION(func); @@ -370,17 +371,18 @@ static PyObject * cfunction_vectorcall_FASTCALL( PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) { - if (cfunction_check_kwargs(func, kwnames)) { + PyThreadState *tstate = _PyThreadState_GET(); + if (cfunction_check_kwargs(tstate, func, kwnames)) { return NULL; } Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); _PyCFunctionFast meth = (_PyCFunctionFast) - cfunction_enter_call(func); + cfunction_enter_call(tstate, func); if (meth == NULL) { return NULL; } PyObject *result = meth(PyCFunction_GET_SELF(func), args, nargs); - Py_LeaveRecursiveCall(); + _Py_LeaveRecursiveCall(tstate); return result; } @@ -388,14 +390,15 @@ static PyObject * cfunction_vectorcall_FASTCALL_KEYWORDS( PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) { + PyThreadState *tstate = _PyThreadState_GET(); Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); _PyCFunctionFastWithKeywords meth = (_PyCFunctionFastWithKeywords) - cfunction_enter_call(func); + cfunction_enter_call(tstate, func); if (meth == NULL) { return NULL; } PyObject *result = meth(PyCFunction_GET_SELF(func), args, nargs, kwnames); - Py_LeaveRecursiveCall(); + _Py_LeaveRecursiveCall(tstate); return result; } @@ -403,21 +406,23 @@ static PyObject * cfunction_vectorcall_NOARGS( PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) { - if (cfunction_check_kwargs(func, kwnames)) { + PyThreadState *tstate = _PyThreadState_GET(); + if (cfunction_check_kwargs(tstate, func, kwnames)) { return NULL; } Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); if (nargs != 0) { - PyErr_Format(PyExc_TypeError, - "%.200s() takes no arguments (%zd given)", get_name(func), nargs); + _PyErr_Format(tstate, PyExc_TypeError, + "%.200s() takes no arguments (%zd given)", + get_name(func), nargs); return NULL; } - PyCFunction meth = (PyCFunction)cfunction_enter_call(func); + PyCFunction meth = (PyCFunction)cfunction_enter_call(tstate, func); if (meth == NULL) { return NULL; } PyObject *result = meth(PyCFunction_GET_SELF(func), NULL); - Py_LeaveRecursiveCall(); + _Py_LeaveRecursiveCall(tstate); return result; } @@ -425,22 +430,23 @@ static PyObject * cfunction_vectorcall_O( PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) { - if (cfunction_check_kwargs(func, kwnames)) { + PyThreadState *tstate = _PyThreadState_GET(); + if (cfunction_check_kwargs(tstate, func, kwnames)) { return NULL; } Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); if (nargs != 1) { - PyErr_Format(PyExc_TypeError, - "%.200s() takes exactly one argument (%zd given)", - get_name(func), nargs); + _PyErr_Format(tstate, PyExc_TypeError, + "%.200s() takes exactly one argument (%zd given)", + get_name(func), nargs); return NULL; } - PyCFunction meth = (PyCFunction)cfunction_enter_call(func); + PyCFunction meth = (PyCFunction)cfunction_enter_call(tstate, func); if (meth == NULL) { return NULL; } PyObject *result = meth(PyCFunction_GET_SELF(func), args[0]); - Py_LeaveRecursiveCall(); + _Py_LeaveRecursiveCall(tstate); return result; } diff --git a/Objects/object.c b/Objects/object.c index 2c8e823f05e..9536d467f5f 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -2,10 +2,11 @@ /* Generic object operations; and implementation of None */ #include "Python.h" +#include "pycore_context.h" #include "pycore_initconfig.h" #include "pycore_object.h" +#include "pycore_pyerrors.h" #include "pycore_pystate.h" -#include "pycore_context.h" #include "frameobject.h" #include "interpreteridobject.h" @@ -525,31 +526,37 @@ PyObject_Repr(PyObject *v) return PyUnicode_FromFormat("<%s object at %p>", v->ob_type->tp_name, v); + PyThreadState *tstate = _PyThreadState_GET(); #ifdef Py_DEBUG /* PyObject_Repr() must not be called with an exception set, because it can clear it (directly or indirectly) and so the caller loses its exception */ - assert(!PyErr_Occurred()); + assert(!_PyErr_Occurred(tstate)); #endif /* It is possible for a type to have a tp_repr representation that loops infinitely. */ - if (Py_EnterRecursiveCall(" while getting the repr of an object")) + if (_Py_EnterRecursiveCall(tstate, + " while getting the repr of an object")) { return NULL; + } res = (*v->ob_type->tp_repr)(v); - Py_LeaveRecursiveCall(); - if (res == NULL) + _Py_LeaveRecursiveCall(tstate); + + if (res == NULL) { return NULL; + } if (!PyUnicode_Check(res)) { - PyErr_Format(PyExc_TypeError, - "__repr__ returned non-string (type %.200s)", - res->ob_type->tp_name); + _PyErr_Format(tstate, PyExc_TypeError, + "__repr__ returned non-string (type %.200s)", + res->ob_type->tp_name); Py_DECREF(res); return NULL; } #ifndef Py_DEBUG - if (PyUnicode_READY(res) < 0) + if (PyUnicode_READY(res) < 0) { return NULL; + } #endif return res; } @@ -579,31 +586,36 @@ PyObject_Str(PyObject *v) if (Py_TYPE(v)->tp_str == NULL) return PyObject_Repr(v); + PyThreadState *tstate = _PyThreadState_GET(); #ifdef Py_DEBUG /* PyObject_Str() must not be called with an exception set, because it can clear it (directly or indirectly) and so the caller loses its exception */ - assert(!PyErr_Occurred()); + assert(!_PyErr_Occurred(tstate)); #endif /* It is possible for a type to have a tp_str representation that loops infinitely. */ - if (Py_EnterRecursiveCall(" while getting the str of an object")) + if (_Py_EnterRecursiveCall(tstate, " while getting the str of an object")) { return NULL; + } res = (*Py_TYPE(v)->tp_str)(v); - Py_LeaveRecursiveCall(); - if (res == NULL) + _Py_LeaveRecursiveCall(tstate); + + if (res == NULL) { return NULL; + } if (!PyUnicode_Check(res)) { - PyErr_Format(PyExc_TypeError, - "__str__ returned non-string (type %.200s)", - Py_TYPE(res)->tp_name); + _PyErr_Format(tstate, PyExc_TypeError, + "__str__ returned non-string (type %.200s)", + Py_TYPE(res)->tp_name); Py_DECREF(res); return NULL; } #ifndef Py_DEBUG - if (PyUnicode_READY(res) < 0) + if (PyUnicode_READY(res) < 0) { return NULL; + } #endif assert(_PyUnicode_CheckConsistency(res, 1)); return res; @@ -707,7 +719,7 @@ static const char * const opstrings[] = {"<", "<=", "==", "!=", ">", ">="}; /* Perform a rich comparison, raising TypeError when the requested comparison operator is not supported. */ static PyObject * -do_richcompare(PyObject *v, PyObject *w, int op) +do_richcompare(PyThreadState *tstate, PyObject *v, PyObject *w, int op) { richcmpfunc f; PyObject *res; @@ -744,11 +756,11 @@ do_richcompare(PyObject *v, PyObject *w, int op) res = (v != w) ? Py_True : Py_False; break; default: - PyErr_Format(PyExc_TypeError, - "'%s' not supported between instances of '%.100s' and '%.100s'", - opstrings[op], - v->ob_type->tp_name, - w->ob_type->tp_name); + _PyErr_Format(tstate, PyExc_TypeError, + "'%s' not supported between instances of '%.100s' and '%.100s'", + opstrings[op], + v->ob_type->tp_name, + w->ob_type->tp_name); return NULL; } Py_INCREF(res); @@ -761,18 +773,20 @@ do_richcompare(PyObject *v, PyObject *w, int op) PyObject * PyObject_RichCompare(PyObject *v, PyObject *w, int op) { - PyObject *res; + PyThreadState *tstate = _PyThreadState_GET(); assert(Py_LT <= op && op <= Py_GE); if (v == NULL || w == NULL) { - if (!PyErr_Occurred()) + if (!_PyErr_Occurred(tstate)) { PyErr_BadInternalCall(); + } return NULL; } - if (Py_EnterRecursiveCall(" in comparison")) + if (_Py_EnterRecursiveCall(tstate, " in comparison")) { return NULL; - res = do_richcompare(v, w, op); - Py_LeaveRecursiveCall(); + } + PyObject *res = do_richcompare(tstate, v, w, op); + _Py_LeaveRecursiveCall(tstate); return res; } diff --git a/Python/ceval.c b/Python/ceval.c index 881a7dd629b..a01fa35dca2 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -659,16 +659,15 @@ Py_SetRecursionLimit(int new_limit) _Py_CheckRecursionLimit = ceval->recursion_limit; } -/* the macro Py_EnterRecursiveCall() only calls _Py_CheckRecursiveCall() +/* The function _Py_EnterRecursiveCall() only calls _Py_CheckRecursiveCall() if the recursion_depth reaches _Py_CheckRecursionLimit. If USE_STACKCHECK, the macro decrements _Py_CheckRecursionLimit to guarantee that _Py_CheckRecursiveCall() is regularly called. Without USE_STACKCHECK, there is no need for this. */ int -_Py_CheckRecursiveCall(const char *where) +_Py_CheckRecursiveCall(PyThreadState *tstate, const char *where) { _PyRuntimeState *runtime = &_PyRuntime; - PyThreadState *tstate = _PyRuntimeState_GetThreadState(runtime); int recursion_limit = runtime->ceval.recursion_limit; #ifdef USE_STACKCHECK @@ -1073,8 +1072,9 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag) /* Start of code */ /* push frame */ - if (Py_EnterRecursiveCall("")) + if (_Py_EnterRecursiveCall(tstate, "")) { return NULL; + } tstate->frame = f; @@ -3810,7 +3810,7 @@ exit_yielding: exit_eval_frame: if (PyDTrace_FUNCTION_RETURN_ENABLED()) dtrace_function_return(f); - Py_LeaveRecursiveCall(); + _Py_LeaveRecursiveCall(tstate); f->f_executing = 0; tstate->frame = f->f_back; @@ -5641,12 +5641,12 @@ maybe_dtrace_line(PyFrameObject *frame, int Py_EnterRecursiveCall(const char *where) { - return _Py_EnterRecursiveCall_macro(where); + return _Py_EnterRecursiveCall_inline(where); } #undef Py_LeaveRecursiveCall void Py_LeaveRecursiveCall(void) { - _Py_LeaveRecursiveCall_macro(); + _Py_LeaveRecursiveCall_inline(); }