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().
This commit is contained in:
Victor Stinner 2019-11-05 00:51:22 +01:00 committed by GitHub
parent f4b1e3d7c6
commit be434dc038
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 201 additions and 136 deletions

View File

@ -11,20 +11,31 @@ PyAPI_DATA(int) _Py_CheckRecursionLimit;
#ifdef USE_STACKCHECK #ifdef USE_STACKCHECK
/* With USE_STACKCHECK macro defined, trigger stack checks in /* With USE_STACKCHECK macro defined, trigger stack checks in
_Py_CheckRecursiveCall() on every 64th call to Py_EnterRecursiveCall. */ _Py_CheckRecursiveCall() on every 64th call to Py_EnterRecursiveCall. */
# define _Py_MakeRecCheck(x) \ static inline int _Py_MakeRecCheck(PyThreadState *tstate) {
(++(x) > _Py_CheckRecursionLimit || \ return (++tstate->recursion_depth > _Py_CheckRecursionLimit
++(PyThreadState_GET()->stackcheck_counter) > 64) || ++tstate->stackcheck_counter > 64);
}
#else #else
# define _Py_MakeRecCheck(x) (++(x) > _Py_CheckRecursionLimit) static inline int _Py_MakeRecCheck(PyThreadState *tstate) {
return (++tstate->recursion_depth > _Py_CheckRecursionLimit);
}
#endif #endif
PyAPI_FUNC(int) _Py_CheckRecursiveCall(const char *where); PyAPI_FUNC(int) _Py_CheckRecursiveCall(
PyThreadState *tstate,
const char *where);
#define _Py_EnterRecursiveCall_macro(where) \ static inline int _Py_EnterRecursiveCall(PyThreadState *tstate,
(_Py_MakeRecCheck(PyThreadState_GET()->recursion_depth) && \ const char *where) {
_Py_CheckRecursiveCall(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 /* 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) \ #define _Py_MakeEndRecCheck(x) \
(--(x) < _Py_RecursionLimitLowerWaterMark(_Py_CheckRecursionLimit)) (--(x) < _Py_RecursionLimitLowerWaterMark(_Py_CheckRecursionLimit))
#define _Py_LeaveRecursiveCall_macro() \ static inline void _Py_LeaveRecursiveCall(PyThreadState *tstate) {
do{ if(_Py_MakeEndRecCheck(PyThreadState_GET()->recursion_depth)) \ if (_Py_MakeEndRecCheck(tstate->recursion_depth)) {
PyThreadState_GET()->overflowed = 0; \ tstate->overflowed = 0;
} while(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 #ifdef __cplusplus
} }

View File

@ -1,6 +1,7 @@
/* Abstract Object Interface (many thanks to Jim Fulton) */ /* Abstract Object Interface (many thanks to Jim Fulton) */
#include "Python.h" #include "Python.h"
#include "pycore_pyerrors.h"
#include "pycore_pystate.h" #include "pycore_pystate.h"
#include <ctype.h> #include <ctype.h>
#include "structmember.h" /* we need the offsetof() macro from there */ #include "structmember.h" /* we need the offsetof() macro from there */
@ -2459,8 +2460,8 @@ recursive_isinstance(PyObject *inst, PyObject *cls)
return retval; return retval;
} }
int static int
PyObject_IsInstance(PyObject *inst, PyObject *cls) object_isinstance(PyThreadState *tstate, PyObject *inst, PyObject *cls)
{ {
_Py_IDENTIFIER(__instancecheck__); _Py_IDENTIFIER(__instancecheck__);
PyObject *checker; PyObject *checker;
@ -2475,34 +2476,31 @@ PyObject_IsInstance(PyObject *inst, PyObject *cls)
} }
if (PyTuple_Check(cls)) { if (PyTuple_Check(cls)) {
Py_ssize_t i; if (_Py_EnterRecursiveCall(tstate, " in __instancecheck__")) {
Py_ssize_t n;
int r = 0;
if (Py_EnterRecursiveCall(" in __instancecheck__"))
return -1; 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); PyObject *item = PyTuple_GET_ITEM(cls, i);
r = PyObject_IsInstance(inst, item); r = object_isinstance(tstate, inst, item);
if (r != 0) if (r != 0)
/* either found it, or got an error */ /* either found it, or got an error */
break; break;
} }
Py_LeaveRecursiveCall(); _Py_LeaveRecursiveCall(tstate);
return r; return r;
} }
checker = _PyObject_LookupSpecial(cls, &PyId___instancecheck__); checker = _PyObject_LookupSpecial(cls, &PyId___instancecheck__);
if (checker != NULL) { if (checker != NULL) {
PyObject *res;
int ok = -1; int ok = -1;
if (Py_EnterRecursiveCall(" in __instancecheck__")) { if (_Py_EnterRecursiveCall(tstate, " in __instancecheck__")) {
Py_DECREF(checker); Py_DECREF(checker);
return ok; return ok;
} }
res = _PyObject_CallOneArg(checker, inst); PyObject *res = _PyObject_CallOneArg(checker, inst);
Py_LeaveRecursiveCall(); _Py_LeaveRecursiveCall(tstate);
Py_DECREF(checker); Py_DECREF(checker);
if (res != NULL) { if (res != NULL) {
ok = PyObject_IsTrue(res); ok = PyObject_IsTrue(res);
@ -2510,12 +2508,23 @@ PyObject_IsInstance(PyObject *inst, PyObject *cls)
} }
return ok; return ok;
} }
else if (PyErr_Occurred()) else if (_PyErr_Occurred(tstate)) {
return -1; return -1;
}
/* Probably never reached anymore. */ /* Probably never reached anymore. */
return recursive_isinstance(inst, cls); return recursive_isinstance(inst, cls);
} }
int
PyObject_IsInstance(PyObject *inst, PyObject *cls)
{
PyThreadState *tstate = _PyThreadState_GET();
return object_isinstance(tstate, inst, cls);
}
static int static int
recursive_issubclass(PyObject *derived, PyObject *cls) recursive_issubclass(PyObject *derived, PyObject *cls)
{ {
@ -2534,8 +2543,8 @@ recursive_issubclass(PyObject *derived, PyObject *cls)
return abstract_issubclass(derived, cls); return abstract_issubclass(derived, cls);
} }
int static int
PyObject_IsSubclass(PyObject *derived, PyObject *cls) object_issubclass(PyThreadState *tstate, PyObject *derived, PyObject *cls)
{ {
_Py_IDENTIFIER(__subclasscheck__); _Py_IDENTIFIER(__subclasscheck__);
PyObject *checker; PyObject *checker;
@ -2549,34 +2558,32 @@ PyObject_IsSubclass(PyObject *derived, PyObject *cls)
} }
if (PyTuple_Check(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; 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); PyObject *item = PyTuple_GET_ITEM(cls, i);
r = PyObject_IsSubclass(derived, item); r = object_issubclass(tstate, derived, item);
if (r != 0) if (r != 0)
/* either found it, or got an error */ /* either found it, or got an error */
break; break;
} }
Py_LeaveRecursiveCall(); _Py_LeaveRecursiveCall(tstate);
return r; return r;
} }
checker = _PyObject_LookupSpecial(cls, &PyId___subclasscheck__); checker = _PyObject_LookupSpecial(cls, &PyId___subclasscheck__);
if (checker != NULL) { if (checker != NULL) {
PyObject *res;
int ok = -1; int ok = -1;
if (Py_EnterRecursiveCall(" in __subclasscheck__")) { if (_Py_EnterRecursiveCall(tstate, " in __subclasscheck__")) {
Py_DECREF(checker); Py_DECREF(checker);
return ok; return ok;
} }
res = _PyObject_CallOneArg(checker, derived); PyObject *res = _PyObject_CallOneArg(checker, derived);
Py_LeaveRecursiveCall(); _Py_LeaveRecursiveCall(tstate);
Py_DECREF(checker); Py_DECREF(checker);
if (res != NULL) { if (res != NULL) {
ok = PyObject_IsTrue(res); ok = PyObject_IsTrue(res);
@ -2584,12 +2591,23 @@ PyObject_IsSubclass(PyObject *derived, PyObject *cls)
} }
return ok; return ok;
} }
else if (PyErr_Occurred()) else if (_PyErr_Occurred(tstate)) {
return -1; return -1;
}
/* Probably never reached anymore. */ /* Probably never reached anymore. */
return recursive_issubclass(derived, cls); return recursive_issubclass(derived, cls);
} }
int
PyObject_IsSubclass(PyObject *derived, PyObject *cls)
{
PyThreadState *tstate = _PyThreadState_GET();
return object_issubclass(tstate, derived, cls);
}
int int
_PyObject_RealIsInstance(PyObject *inst, PyObject *cls) _PyObject_RealIsInstance(PyObject *inst, PyObject *cls)
{ {

View File

@ -1,5 +1,6 @@
#include "Python.h" #include "Python.h"
#include "pycore_object.h" #include "pycore_object.h"
#include "pycore_pyerrors.h"
#include "pycore_pystate.h" #include "pycore_pystate.h"
#include "pycore_tupleobject.h" #include "pycore_tupleobject.h"
#include "frameobject.h" #include "frameobject.h"
@ -126,11 +127,14 @@ _PyObject_FastCallDict(PyObject *callable, PyObject *const *args,
PyObject * PyObject *
_PyObject_MakeTpCall(PyObject *callable, PyObject *const *args, Py_ssize_t nargs, PyObject *keywords) _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 /* Slow path: build a temporary tuple for positional arguments and a
* temporary dictionary for keyword arguments (if any) */ * temporary dictionary for keyword arguments (if any) */
ternaryfunc call = Py_TYPE(callable)->tp_call; ternaryfunc call = Py_TYPE(callable)->tp_call;
if (call == NULL) { if (call == NULL) {
PyErr_Format(PyExc_TypeError, "'%.200s' object is not callable", _PyErr_Format(tstate, PyExc_TypeError,
"'%.200s' object is not callable",
Py_TYPE(callable)->tp_name); Py_TYPE(callable)->tp_name);
return NULL; return NULL;
} }
@ -162,10 +166,10 @@ _PyObject_MakeTpCall(PyObject *callable, PyObject *const *args, Py_ssize_t nargs
} }
PyObject *result = NULL; 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); result = call(callable, argstuple, kwdict);
Py_LeaveRecursiveCall(); _Py_LeaveRecursiveCall(tstate);
} }
Py_DECREF(argstuple); Py_DECREF(argstuple);
@ -220,13 +224,14 @@ PyVectorcall_Call(PyObject *callable, PyObject *tuple, PyObject *kwargs)
PyObject * PyObject *
PyObject_Call(PyObject *callable, PyObject *args, PyObject *kwargs) PyObject_Call(PyObject *callable, PyObject *args, PyObject *kwargs)
{ {
PyThreadState *tstate = _PyThreadState_GET();
ternaryfunc call; ternaryfunc call;
PyObject *result; PyObject *result;
/* PyObject_Call() must not be called with an exception set, /* PyObject_Call() must not be called with an exception set,
because it can clear it (directly or indirectly) and so the because it can clear it (directly or indirectly) and so the
caller loses its exception */ caller loses its exception */
assert(!PyErr_Occurred()); assert(!_PyErr_Occurred(tstate));
assert(PyTuple_Check(args)); assert(PyTuple_Check(args));
assert(kwargs == NULL || PyDict_Check(kwargs)); assert(kwargs == NULL || PyDict_Check(kwargs));
@ -236,17 +241,19 @@ PyObject_Call(PyObject *callable, PyObject *args, PyObject *kwargs)
else { else {
call = callable->ob_type->tp_call; call = callable->ob_type->tp_call;
if (call == NULL) { if (call == NULL) {
PyErr_Format(PyExc_TypeError, "'%.200s' object is not callable", _PyErr_Format(tstate, PyExc_TypeError,
"'%.200s' object is not callable",
callable->ob_type->tp_name); callable->ob_type->tp_name);
return NULL; return NULL;
} }
if (Py_EnterRecursiveCall(" while calling a Python object")) if (_Py_EnterRecursiveCall(tstate, " while calling a Python object")) {
return NULL; return NULL;
}
result = (*call)(callable, args, kwargs); result = (*call)(callable, args, kwargs);
Py_LeaveRecursiveCall(); _Py_LeaveRecursiveCall(tstate);
return _Py_CheckFunctionResult(callable, result, NULL); 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, function_code_fastcall(PyCodeObject *co, PyObject *const *args, Py_ssize_t nargs,
PyObject *globals) PyObject *globals)
{ {
PyFrameObject *f;
PyThreadState *tstate = _PyThreadState_GET();
PyObject **fastlocals;
Py_ssize_t i;
PyObject *result;
assert(globals != NULL); assert(globals != NULL);
PyThreadState *tstate = _PyThreadState_GET();
assert(tstate != NULL);
/* XXX Perhaps we should create a specialized /* XXX Perhaps we should create a specialized
_PyFrame_New_NoTrack() that doesn't take locals, but does _PyFrame_New_NoTrack() that doesn't take locals, but does
take builtins without sanity checking them. take builtins without sanity checking them.
*/ */
assert(tstate != NULL); PyFrameObject *f = _PyFrame_New_NoTrack(tstate, co, globals, NULL);
f = _PyFrame_New_NoTrack(tstate, co, globals, NULL);
if (f == NULL) { if (f == NULL) {
return 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); Py_INCREF(*args);
fastlocals[i] = *args++; fastlocals[i] = *args++;
} }
result = PyEval_EvalFrameEx(f,0); PyObject *result = PyEval_EvalFrameEx(f, 0);
if (Py_REFCNT(f) > 1) { if (Py_REFCNT(f) > 1) {
Py_DECREF(f); Py_DECREF(f);

View File

@ -271,9 +271,9 @@ method_check_args(PyObject *func, PyObject *const *args, Py_ssize_t nargs, PyObj
} }
static inline funcptr 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 NULL;
} }
return (funcptr)((PyMethodDescrObject *)func)->d_method->ml_meth; return (funcptr)((PyMethodDescrObject *)func)->d_method->ml_meth;
@ -284,6 +284,7 @@ static PyObject *
method_vectorcall_VARARGS( method_vectorcall_VARARGS(
PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames)
{ {
PyThreadState *tstate = _PyThreadState_GET();
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
if (method_check_args(func, args, nargs, kwnames)) { if (method_check_args(func, args, nargs, kwnames)) {
return NULL; return NULL;
@ -292,14 +293,14 @@ method_vectorcall_VARARGS(
if (argstuple == NULL) { if (argstuple == NULL) {
return NULL; return NULL;
} }
PyCFunction meth = (PyCFunction)method_enter_call(func); PyCFunction meth = (PyCFunction)method_enter_call(tstate, func);
if (meth == NULL) { if (meth == NULL) {
Py_DECREF(argstuple); Py_DECREF(argstuple);
return NULL; return NULL;
} }
PyObject *result = meth(args[0], argstuple); PyObject *result = meth(args[0], argstuple);
Py_DECREF(argstuple); Py_DECREF(argstuple);
Py_LeaveRecursiveCall(); _Py_LeaveRecursiveCall(tstate);
return result; return result;
} }
@ -307,6 +308,7 @@ static PyObject *
method_vectorcall_VARARGS_KEYWORDS( method_vectorcall_VARARGS_KEYWORDS(
PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames)
{ {
PyThreadState *tstate = _PyThreadState_GET();
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
if (method_check_args(func, args, nargs, NULL)) { if (method_check_args(func, args, nargs, NULL)) {
return NULL; return NULL;
@ -325,12 +327,12 @@ method_vectorcall_VARARGS_KEYWORDS(
} }
} }
PyCFunctionWithKeywords meth = (PyCFunctionWithKeywords) PyCFunctionWithKeywords meth = (PyCFunctionWithKeywords)
method_enter_call(func); method_enter_call(tstate, func);
if (meth == NULL) { if (meth == NULL) {
goto exit; goto exit;
} }
result = meth(args[0], argstuple, kwdict); result = meth(args[0], argstuple, kwdict);
Py_LeaveRecursiveCall(); _Py_LeaveRecursiveCall(tstate);
exit: exit:
Py_DECREF(argstuple); Py_DECREF(argstuple);
Py_XDECREF(kwdict); Py_XDECREF(kwdict);
@ -341,17 +343,18 @@ static PyObject *
method_vectorcall_FASTCALL( method_vectorcall_FASTCALL(
PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames)
{ {
PyThreadState *tstate = _PyThreadState_GET();
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
if (method_check_args(func, args, nargs, kwnames)) { if (method_check_args(func, args, nargs, kwnames)) {
return NULL; return NULL;
} }
_PyCFunctionFast meth = (_PyCFunctionFast) _PyCFunctionFast meth = (_PyCFunctionFast)
method_enter_call(func); method_enter_call(tstate, func);
if (meth == NULL) { if (meth == NULL) {
return NULL; return NULL;
} }
PyObject *result = meth(args[0], args+1, nargs-1); PyObject *result = meth(args[0], args+1, nargs-1);
Py_LeaveRecursiveCall(); _Py_LeaveRecursiveCall(tstate);
return result; return result;
} }
@ -359,17 +362,18 @@ static PyObject *
method_vectorcall_FASTCALL_KEYWORDS( method_vectorcall_FASTCALL_KEYWORDS(
PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames)
{ {
PyThreadState *tstate = _PyThreadState_GET();
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
if (method_check_args(func, args, nargs, NULL)) { if (method_check_args(func, args, nargs, NULL)) {
return NULL; return NULL;
} }
_PyCFunctionFastWithKeywords meth = (_PyCFunctionFastWithKeywords) _PyCFunctionFastWithKeywords meth = (_PyCFunctionFastWithKeywords)
method_enter_call(func); method_enter_call(tstate, func);
if (meth == NULL) { if (meth == NULL) {
return NULL; return NULL;
} }
PyObject *result = meth(args[0], args+1, nargs-1, kwnames); PyObject *result = meth(args[0], args+1, nargs-1, kwnames);
Py_LeaveRecursiveCall(); _Py_LeaveRecursiveCall(tstate);
return result; return result;
} }
@ -377,6 +381,7 @@ static PyObject *
method_vectorcall_NOARGS( method_vectorcall_NOARGS(
PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames)
{ {
PyThreadState *tstate = _PyThreadState_GET();
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
if (method_check_args(func, args, nargs, kwnames)) { if (method_check_args(func, args, nargs, kwnames)) {
return NULL; return NULL;
@ -386,12 +391,12 @@ method_vectorcall_NOARGS(
"%.200s() takes no arguments (%zd given)", get_name(func), nargs-1); "%.200s() takes no arguments (%zd given)", get_name(func), nargs-1);
return NULL; return NULL;
} }
PyCFunction meth = (PyCFunction)method_enter_call(func); PyCFunction meth = (PyCFunction)method_enter_call(tstate, func);
if (meth == NULL) { if (meth == NULL) {
return NULL; return NULL;
} }
PyObject *result = meth(args[0], NULL); PyObject *result = meth(args[0], NULL);
Py_LeaveRecursiveCall(); _Py_LeaveRecursiveCall(tstate);
return result; return result;
} }
@ -399,6 +404,7 @@ static PyObject *
method_vectorcall_O( method_vectorcall_O(
PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames)
{ {
PyThreadState *tstate = _PyThreadState_GET();
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
if (method_check_args(func, args, nargs, kwnames)) { if (method_check_args(func, args, nargs, kwnames)) {
return NULL; return NULL;
@ -409,12 +415,12 @@ method_vectorcall_O(
get_name(func), nargs-1); get_name(func), nargs-1);
return NULL; return NULL;
} }
PyCFunction meth = (PyCFunction)method_enter_call(func); PyCFunction meth = (PyCFunction)method_enter_call(tstate, func);
if (meth == NULL) { if (meth == NULL) {
return NULL; return NULL;
} }
PyObject *result = meth(args[0], args[1]); PyObject *result = meth(args[0], args[1]);
Py_LeaveRecursiveCall(); _Py_LeaveRecursiveCall(tstate);
return result; return result;
} }

View File

@ -3,6 +3,7 @@
#include "Python.h" #include "Python.h"
#include "pycore_object.h" #include "pycore_object.h"
#include "pycore_pyerrors.h"
#include "pycore_pymem.h" #include "pycore_pymem.h"
#include "pycore_pystate.h" #include "pycore_pystate.h"
#include "structmember.h" #include "structmember.h"
@ -344,12 +345,12 @@ get_name(PyObject *func)
typedef void (*funcptr)(void); typedef void (*funcptr)(void);
static inline int 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)); assert(PyCFunction_Check(func));
if (kwnames && PyTuple_GET_SIZE(kwnames)) { if (kwnames && PyTuple_GET_SIZE(kwnames)) {
PyErr_Format(PyExc_TypeError, _PyErr_Format(tstate, PyExc_TypeError,
"%.200s() takes no keyword arguments", get_name(func)); "%.200s() takes no keyword arguments", get_name(func));
return -1; return -1;
} }
@ -357,9 +358,9 @@ cfunction_check_kwargs(PyObject *func, PyObject *kwnames)
} }
static inline funcptr 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 NULL;
} }
return (funcptr)PyCFunction_GET_FUNCTION(func); return (funcptr)PyCFunction_GET_FUNCTION(func);
@ -370,17 +371,18 @@ static PyObject *
cfunction_vectorcall_FASTCALL( cfunction_vectorcall_FASTCALL(
PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) 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; return NULL;
} }
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
_PyCFunctionFast meth = (_PyCFunctionFast) _PyCFunctionFast meth = (_PyCFunctionFast)
cfunction_enter_call(func); cfunction_enter_call(tstate, func);
if (meth == NULL) { if (meth == NULL) {
return NULL; return NULL;
} }
PyObject *result = meth(PyCFunction_GET_SELF(func), args, nargs); PyObject *result = meth(PyCFunction_GET_SELF(func), args, nargs);
Py_LeaveRecursiveCall(); _Py_LeaveRecursiveCall(tstate);
return result; return result;
} }
@ -388,14 +390,15 @@ static PyObject *
cfunction_vectorcall_FASTCALL_KEYWORDS( cfunction_vectorcall_FASTCALL_KEYWORDS(
PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames)
{ {
PyThreadState *tstate = _PyThreadState_GET();
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
_PyCFunctionFastWithKeywords meth = (_PyCFunctionFastWithKeywords) _PyCFunctionFastWithKeywords meth = (_PyCFunctionFastWithKeywords)
cfunction_enter_call(func); cfunction_enter_call(tstate, func);
if (meth == NULL) { if (meth == NULL) {
return NULL; return NULL;
} }
PyObject *result = meth(PyCFunction_GET_SELF(func), args, nargs, kwnames); PyObject *result = meth(PyCFunction_GET_SELF(func), args, nargs, kwnames);
Py_LeaveRecursiveCall(); _Py_LeaveRecursiveCall(tstate);
return result; return result;
} }
@ -403,21 +406,23 @@ static PyObject *
cfunction_vectorcall_NOARGS( cfunction_vectorcall_NOARGS(
PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) 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; return NULL;
} }
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
if (nargs != 0) { if (nargs != 0) {
PyErr_Format(PyExc_TypeError, _PyErr_Format(tstate, PyExc_TypeError,
"%.200s() takes no arguments (%zd given)", get_name(func), nargs); "%.200s() takes no arguments (%zd given)",
get_name(func), nargs);
return NULL; return NULL;
} }
PyCFunction meth = (PyCFunction)cfunction_enter_call(func); PyCFunction meth = (PyCFunction)cfunction_enter_call(tstate, func);
if (meth == NULL) { if (meth == NULL) {
return NULL; return NULL;
} }
PyObject *result = meth(PyCFunction_GET_SELF(func), NULL); PyObject *result = meth(PyCFunction_GET_SELF(func), NULL);
Py_LeaveRecursiveCall(); _Py_LeaveRecursiveCall(tstate);
return result; return result;
} }
@ -425,22 +430,23 @@ static PyObject *
cfunction_vectorcall_O( cfunction_vectorcall_O(
PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) 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; return NULL;
} }
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
if (nargs != 1) { if (nargs != 1) {
PyErr_Format(PyExc_TypeError, _PyErr_Format(tstate, PyExc_TypeError,
"%.200s() takes exactly one argument (%zd given)", "%.200s() takes exactly one argument (%zd given)",
get_name(func), nargs); get_name(func), nargs);
return NULL; return NULL;
} }
PyCFunction meth = (PyCFunction)cfunction_enter_call(func); PyCFunction meth = (PyCFunction)cfunction_enter_call(tstate, func);
if (meth == NULL) { if (meth == NULL) {
return NULL; return NULL;
} }
PyObject *result = meth(PyCFunction_GET_SELF(func), args[0]); PyObject *result = meth(PyCFunction_GET_SELF(func), args[0]);
Py_LeaveRecursiveCall(); _Py_LeaveRecursiveCall(tstate);
return result; return result;
} }

View File

@ -2,10 +2,11 @@
/* Generic object operations; and implementation of None */ /* Generic object operations; and implementation of None */
#include "Python.h" #include "Python.h"
#include "pycore_context.h"
#include "pycore_initconfig.h" #include "pycore_initconfig.h"
#include "pycore_object.h" #include "pycore_object.h"
#include "pycore_pyerrors.h"
#include "pycore_pystate.h" #include "pycore_pystate.h"
#include "pycore_context.h"
#include "frameobject.h" #include "frameobject.h"
#include "interpreteridobject.h" #include "interpreteridobject.h"
@ -525,31 +526,37 @@ PyObject_Repr(PyObject *v)
return PyUnicode_FromFormat("<%s object at %p>", return PyUnicode_FromFormat("<%s object at %p>",
v->ob_type->tp_name, v); v->ob_type->tp_name, v);
PyThreadState *tstate = _PyThreadState_GET();
#ifdef Py_DEBUG #ifdef Py_DEBUG
/* PyObject_Repr() must not be called with an exception set, /* PyObject_Repr() must not be called with an exception set,
because it can clear it (directly or indirectly) and so the because it can clear it (directly or indirectly) and so the
caller loses its exception */ caller loses its exception */
assert(!PyErr_Occurred()); assert(!_PyErr_Occurred(tstate));
#endif #endif
/* It is possible for a type to have a tp_repr representation that loops /* It is possible for a type to have a tp_repr representation that loops
infinitely. */ infinitely. */
if (Py_EnterRecursiveCall(" while getting the repr of an object")) if (_Py_EnterRecursiveCall(tstate,
" while getting the repr of an object")) {
return NULL; return NULL;
}
res = (*v->ob_type->tp_repr)(v); res = (*v->ob_type->tp_repr)(v);
Py_LeaveRecursiveCall(); _Py_LeaveRecursiveCall(tstate);
if (res == NULL)
if (res == NULL) {
return NULL; return NULL;
}
if (!PyUnicode_Check(res)) { if (!PyUnicode_Check(res)) {
PyErr_Format(PyExc_TypeError, _PyErr_Format(tstate, PyExc_TypeError,
"__repr__ returned non-string (type %.200s)", "__repr__ returned non-string (type %.200s)",
res->ob_type->tp_name); res->ob_type->tp_name);
Py_DECREF(res); Py_DECREF(res);
return NULL; return NULL;
} }
#ifndef Py_DEBUG #ifndef Py_DEBUG
if (PyUnicode_READY(res) < 0) if (PyUnicode_READY(res) < 0) {
return NULL; return NULL;
}
#endif #endif
return res; return res;
} }
@ -579,31 +586,36 @@ PyObject_Str(PyObject *v)
if (Py_TYPE(v)->tp_str == NULL) if (Py_TYPE(v)->tp_str == NULL)
return PyObject_Repr(v); return PyObject_Repr(v);
PyThreadState *tstate = _PyThreadState_GET();
#ifdef Py_DEBUG #ifdef Py_DEBUG
/* PyObject_Str() must not be called with an exception set, /* PyObject_Str() must not be called with an exception set,
because it can clear it (directly or indirectly) and so the because it can clear it (directly or indirectly) and so the
caller loses its exception */ caller loses its exception */
assert(!PyErr_Occurred()); assert(!_PyErr_Occurred(tstate));
#endif #endif
/* It is possible for a type to have a tp_str representation that loops /* It is possible for a type to have a tp_str representation that loops
infinitely. */ infinitely. */
if (Py_EnterRecursiveCall(" while getting the str of an object")) if (_Py_EnterRecursiveCall(tstate, " while getting the str of an object")) {
return NULL; return NULL;
}
res = (*Py_TYPE(v)->tp_str)(v); res = (*Py_TYPE(v)->tp_str)(v);
Py_LeaveRecursiveCall(); _Py_LeaveRecursiveCall(tstate);
if (res == NULL)
if (res == NULL) {
return NULL; return NULL;
}
if (!PyUnicode_Check(res)) { if (!PyUnicode_Check(res)) {
PyErr_Format(PyExc_TypeError, _PyErr_Format(tstate, PyExc_TypeError,
"__str__ returned non-string (type %.200s)", "__str__ returned non-string (type %.200s)",
Py_TYPE(res)->tp_name); Py_TYPE(res)->tp_name);
Py_DECREF(res); Py_DECREF(res);
return NULL; return NULL;
} }
#ifndef Py_DEBUG #ifndef Py_DEBUG
if (PyUnicode_READY(res) < 0) if (PyUnicode_READY(res) < 0) {
return NULL; return NULL;
}
#endif #endif
assert(_PyUnicode_CheckConsistency(res, 1)); assert(_PyUnicode_CheckConsistency(res, 1));
return res; return res;
@ -707,7 +719,7 @@ static const char * const opstrings[] = {"<", "<=", "==", "!=", ">", ">="};
/* Perform a rich comparison, raising TypeError when the requested comparison /* Perform a rich comparison, raising TypeError when the requested comparison
operator is not supported. */ operator is not supported. */
static PyObject * static PyObject *
do_richcompare(PyObject *v, PyObject *w, int op) do_richcompare(PyThreadState *tstate, PyObject *v, PyObject *w, int op)
{ {
richcmpfunc f; richcmpfunc f;
PyObject *res; PyObject *res;
@ -744,7 +756,7 @@ do_richcompare(PyObject *v, PyObject *w, int op)
res = (v != w) ? Py_True : Py_False; res = (v != w) ? Py_True : Py_False;
break; break;
default: default:
PyErr_Format(PyExc_TypeError, _PyErr_Format(tstate, PyExc_TypeError,
"'%s' not supported between instances of '%.100s' and '%.100s'", "'%s' not supported between instances of '%.100s' and '%.100s'",
opstrings[op], opstrings[op],
v->ob_type->tp_name, v->ob_type->tp_name,
@ -761,18 +773,20 @@ do_richcompare(PyObject *v, PyObject *w, int op)
PyObject * PyObject *
PyObject_RichCompare(PyObject *v, PyObject *w, int op) PyObject_RichCompare(PyObject *v, PyObject *w, int op)
{ {
PyObject *res; PyThreadState *tstate = _PyThreadState_GET();
assert(Py_LT <= op && op <= Py_GE); assert(Py_LT <= op && op <= Py_GE);
if (v == NULL || w == NULL) { if (v == NULL || w == NULL) {
if (!PyErr_Occurred()) if (!_PyErr_Occurred(tstate)) {
PyErr_BadInternalCall(); PyErr_BadInternalCall();
}
return NULL; return NULL;
} }
if (Py_EnterRecursiveCall(" in comparison")) if (_Py_EnterRecursiveCall(tstate, " in comparison")) {
return NULL; return NULL;
res = do_richcompare(v, w, op); }
Py_LeaveRecursiveCall(); PyObject *res = do_richcompare(tstate, v, w, op);
_Py_LeaveRecursiveCall(tstate);
return res; return res;
} }

View File

@ -659,16 +659,15 @@ Py_SetRecursionLimit(int new_limit)
_Py_CheckRecursionLimit = ceval->recursion_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 the recursion_depth reaches _Py_CheckRecursionLimit.
If USE_STACKCHECK, the macro decrements _Py_CheckRecursionLimit If USE_STACKCHECK, the macro decrements _Py_CheckRecursionLimit
to guarantee that _Py_CheckRecursiveCall() is regularly called. to guarantee that _Py_CheckRecursiveCall() is regularly called.
Without USE_STACKCHECK, there is no need for this. */ Without USE_STACKCHECK, there is no need for this. */
int int
_Py_CheckRecursiveCall(const char *where) _Py_CheckRecursiveCall(PyThreadState *tstate, const char *where)
{ {
_PyRuntimeState *runtime = &_PyRuntime; _PyRuntimeState *runtime = &_PyRuntime;
PyThreadState *tstate = _PyRuntimeState_GetThreadState(runtime);
int recursion_limit = runtime->ceval.recursion_limit; int recursion_limit = runtime->ceval.recursion_limit;
#ifdef USE_STACKCHECK #ifdef USE_STACKCHECK
@ -1073,8 +1072,9 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
/* Start of code */ /* Start of code */
/* push frame */ /* push frame */
if (Py_EnterRecursiveCall("")) if (_Py_EnterRecursiveCall(tstate, "")) {
return NULL; return NULL;
}
tstate->frame = f; tstate->frame = f;
@ -3810,7 +3810,7 @@ exit_yielding:
exit_eval_frame: exit_eval_frame:
if (PyDTrace_FUNCTION_RETURN_ENABLED()) if (PyDTrace_FUNCTION_RETURN_ENABLED())
dtrace_function_return(f); dtrace_function_return(f);
Py_LeaveRecursiveCall(); _Py_LeaveRecursiveCall(tstate);
f->f_executing = 0; f->f_executing = 0;
tstate->frame = f->f_back; tstate->frame = f->f_back;
@ -5641,12 +5641,12 @@ maybe_dtrace_line(PyFrameObject *frame,
int Py_EnterRecursiveCall(const char *where) int Py_EnterRecursiveCall(const char *where)
{ {
return _Py_EnterRecursiveCall_macro(where); return _Py_EnterRecursiveCall_inline(where);
} }
#undef Py_LeaveRecursiveCall #undef Py_LeaveRecursiveCall
void Py_LeaveRecursiveCall(void) void Py_LeaveRecursiveCall(void)
{ {
_Py_LeaveRecursiveCall_macro(); _Py_LeaveRecursiveCall_inline();
} }