Skip to content

Commit 1726909

Browse files
authored
bpo-38644: Pass tstate to _Py_CheckFunctionResult() (pythonGH-17050)
* Add tstate parameter to _Py_CheckFunctionResult() * Add _PyErr_FormatFromCauseTstate() * Replace PyErr_XXX(...) with _PyErr_XXX(state, ...)
1 parent be434dc commit 1726909

7 files changed

Lines changed: 94 additions & 52 deletions

File tree

Include/cpython/abstract.h

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,11 @@ PyAPI_FUNC(PyObject *) _PyStack_AsDict(
3737
40 bytes on the stack. */
3838
#define _PY_FASTCALL_SMALL_STACK 5
3939

40-
PyAPI_FUNC(PyObject *) _Py_CheckFunctionResult(PyObject *callable,
41-
PyObject *result,
42-
const char *where);
40+
PyAPI_FUNC(PyObject *) _Py_CheckFunctionResult(
41+
PyThreadState *tstate,
42+
PyObject *callable,
43+
PyObject *result,
44+
const char *where);
4345

4446
/* === Vectorcall protocol (PEP 590) ============================= */
4547

@@ -98,13 +100,15 @@ _PyObject_Vectorcall(PyObject *callable, PyObject *const *args,
98100
{
99101
assert(kwnames == NULL || PyTuple_Check(kwnames));
100102
assert(args != NULL || PyVectorcall_NARGS(nargsf) == 0);
103+
104+
PyThreadState *tstate = PyThreadState_GET();
101105
vectorcallfunc func = _PyVectorcall_Function(callable);
102106
if (func == NULL) {
103107
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
104108
return _PyObject_MakeTpCall(callable, args, nargs, kwnames);
105109
}
106110
PyObject *res = func(callable, args, nargsf, kwnames);
107-
return _Py_CheckFunctionResult(callable, res, NULL);
111+
return _Py_CheckFunctionResult(tstate, callable, res, NULL);
108112
}
109113

110114
/* Same as _PyObject_Vectorcall except that keyword arguments are passed as

Include/internal/pycore_pyerrors.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,12 @@ PyAPI_FUNC(void) _PyErr_NormalizeException(
5858
PyObject **val,
5959
PyObject **tb);
6060

61+
PyAPI_FUNC(PyObject *) _PyErr_FormatFromCauseTstate(
62+
PyThreadState *tstate,
63+
PyObject *exception,
64+
const char *format,
65+
...);
66+
6167
#ifdef __cplusplus
6268
}
6369
#endif

Objects/call.c

Lines changed: 47 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@
77

88

99
static PyObject *const *
10-
_PyStack_UnpackDict(PyObject *const *args, Py_ssize_t nargs, PyObject *kwargs,
11-
PyObject **p_kwnames);
10+
_PyStack_UnpackDict(PyThreadState *tstate,
11+
PyObject *const *args, Py_ssize_t nargs,
12+
PyObject *kwargs, PyObject **p_kwnames);
1213

1314
static void
1415
_PyStack_UnpackDict_Free(PyObject *const *stack, Py_ssize_t nargs,
@@ -26,22 +27,23 @@ null_error(void)
2627

2728

2829
PyObject*
29-
_Py_CheckFunctionResult(PyObject *callable, PyObject *result, const char *where)
30+
_Py_CheckFunctionResult(PyThreadState *tstate, PyObject *callable,
31+
PyObject *result, const char *where)
3032
{
31-
int err_occurred = (PyErr_Occurred() != NULL);
33+
int err_occurred = (_PyErr_Occurred(tstate) != NULL);
3234

3335
assert((callable != NULL) ^ (where != NULL));
3436

3537
if (result == NULL) {
3638
if (!err_occurred) {
3739
if (callable)
38-
PyErr_Format(PyExc_SystemError,
39-
"%R returned NULL without setting an error",
40-
callable);
40+
_PyErr_Format(tstate, PyExc_SystemError,
41+
"%R returned NULL without setting an error",
42+
callable);
4143
else
42-
PyErr_Format(PyExc_SystemError,
43-
"%s returned NULL without setting an error",
44-
where);
44+
_PyErr_Format(tstate, PyExc_SystemError,
45+
"%s returned NULL without setting an error",
46+
where);
4547
#ifdef Py_DEBUG
4648
/* Ensure that the bug is caught in debug mode */
4749
Py_FatalError("a function returned NULL without setting an error");
@@ -54,14 +56,14 @@ _Py_CheckFunctionResult(PyObject *callable, PyObject *result, const char *where)
5456
Py_DECREF(result);
5557

5658
if (callable) {
57-
_PyErr_FormatFromCause(PyExc_SystemError,
58-
"%R returned a result with an error set",
59-
callable);
59+
_PyErr_FormatFromCauseTstate(
60+
tstate, PyExc_SystemError,
61+
"%R returned a result with an error set", callable);
6062
}
6163
else {
62-
_PyErr_FormatFromCause(PyExc_SystemError,
63-
"%s returned a result with an error set",
64-
where);
64+
_PyErr_FormatFromCauseTstate(
65+
tstate, PyExc_SystemError,
66+
"%s returned a result with an error set", where);
6567
}
6668
#ifdef Py_DEBUG
6769
/* Ensure that the bug is caught in debug mode */
@@ -88,11 +90,13 @@ PyObject *
8890
_PyObject_FastCallDict(PyObject *callable, PyObject *const *args,
8991
size_t nargsf, PyObject *kwargs)
9092
{
93+
assert(callable != NULL);
94+
95+
PyThreadState *tstate = _PyThreadState_GET();
9196
/* _PyObject_FastCallDict() must not be called with an exception set,
9297
because it can clear it (directly or indirectly) and so the
9398
caller loses its exception */
94-
assert(!PyErr_Occurred());
95-
assert(callable != NULL);
99+
assert(!_PyErr_Occurred(tstate));
96100

97101
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
98102
assert(nargs >= 0);
@@ -112,15 +116,17 @@ _PyObject_FastCallDict(PyObject *callable, PyObject *const *args,
112116
else {
113117
PyObject *kwnames;
114118
PyObject *const *newargs;
115-
newargs = _PyStack_UnpackDict(args, nargs, kwargs, &kwnames);
119+
newargs = _PyStack_UnpackDict(tstate,
120+
args, nargs,
121+
kwargs, &kwnames);
116122
if (newargs == NULL) {
117123
return NULL;
118124
}
119125
res = func(callable, newargs,
120126
nargs | PY_VECTORCALL_ARGUMENTS_OFFSET, kwnames);
121127
_PyStack_UnpackDict_Free(newargs, nargs, kwnames);
122128
}
123-
return _Py_CheckFunctionResult(callable, res, NULL);
129+
return _Py_CheckFunctionResult(tstate, callable, res, NULL);
124130
}
125131

126132

@@ -177,26 +183,30 @@ _PyObject_MakeTpCall(PyObject *callable, PyObject *const *args, Py_ssize_t nargs
177183
Py_DECREF(kwdict);
178184
}
179185

180-
result = _Py_CheckFunctionResult(callable, result, NULL);
186+
result = _Py_CheckFunctionResult(tstate, callable, result, NULL);
181187
return result;
182188
}
183189

184190

185191
PyObject *
186192
PyVectorcall_Call(PyObject *callable, PyObject *tuple, PyObject *kwargs)
187193
{
194+
PyThreadState *tstate = _PyThreadState_GET();
195+
188196
/* get vectorcallfunc as in _PyVectorcall_Function, but without
189197
* the _Py_TPFLAGS_HAVE_VECTORCALL check */
190198
Py_ssize_t offset = Py_TYPE(callable)->tp_vectorcall_offset;
191199
if (offset <= 0) {
192-
PyErr_Format(PyExc_TypeError, "'%.200s' object does not support vectorcall",
193-
Py_TYPE(callable)->tp_name);
200+
_PyErr_Format(tstate, PyExc_TypeError,
201+
"'%.200s' object does not support vectorcall",
202+
Py_TYPE(callable)->tp_name);
194203
return NULL;
195204
}
196205
vectorcallfunc func = *(vectorcallfunc *)(((char *)callable) + offset);
197206
if (func == NULL) {
198-
PyErr_Format(PyExc_TypeError, "'%.200s' object does not support vectorcall",
199-
Py_TYPE(callable)->tp_name);
207+
_PyErr_Format(tstate, PyExc_TypeError,
208+
"'%.200s' object does not support vectorcall",
209+
Py_TYPE(callable)->tp_name);
200210
return NULL;
201211
}
202212

@@ -210,14 +220,16 @@ PyVectorcall_Call(PyObject *callable, PyObject *tuple, PyObject *kwargs)
210220
/* Convert arguments & call */
211221
PyObject *const *args;
212222
PyObject *kwnames;
213-
args = _PyStack_UnpackDict(_PyTuple_ITEMS(tuple), nargs, kwargs, &kwnames);
223+
args = _PyStack_UnpackDict(tstate,
224+
_PyTuple_ITEMS(tuple), nargs,
225+
kwargs, &kwnames);
214226
if (args == NULL) {
215227
return NULL;
216228
}
217229
PyObject *result = func(callable, args,
218230
nargs | PY_VECTORCALL_ARGUMENTS_OFFSET, kwnames);
219231
_PyStack_UnpackDict_Free(args, nargs, kwnames);
220-
return _Py_CheckFunctionResult(callable, result, NULL);
232+
return _Py_CheckFunctionResult(tstate, callable, result, NULL);
221233
}
222234

223235

@@ -255,7 +267,7 @@ PyObject_Call(PyObject *callable, PyObject *args, PyObject *kwargs)
255267

256268
_Py_LeaveRecursiveCall(tstate);
257269

258-
return _Py_CheckFunctionResult(callable, result, NULL);
270+
return _Py_CheckFunctionResult(tstate, callable, result, NULL);
259271
}
260272
}
261273

@@ -898,8 +910,9 @@ _PyStack_AsDict(PyObject *const *values, PyObject *kwnames)
898910
899911
When done, you must call _PyStack_UnpackDict_Free(stack, nargs, kwnames) */
900912
static PyObject *const *
901-
_PyStack_UnpackDict(PyObject *const *args, Py_ssize_t nargs, PyObject *kwargs,
902-
PyObject **p_kwnames)
913+
_PyStack_UnpackDict(PyThreadState *tstate,
914+
PyObject *const *args, Py_ssize_t nargs,
915+
PyObject *kwargs, PyObject **p_kwnames)
903916
{
904917
assert(nargs >= 0);
905918
assert(kwargs != NULL);
@@ -911,14 +924,14 @@ _PyStack_UnpackDict(PyObject *const *args, Py_ssize_t nargs, PyObject *kwargs,
911924
* non-negative signed integers, so their difference fits in the type. */
912925
Py_ssize_t maxnargs = PY_SSIZE_T_MAX / sizeof(args[0]) - 1;
913926
if (nargs > maxnargs - nkwargs) {
914-
PyErr_NoMemory();
927+
_PyErr_NoMemory(tstate);
915928
return NULL;
916929
}
917930

918931
/* Add 1 to support PY_VECTORCALL_ARGUMENTS_OFFSET */
919932
PyObject **stack = PyMem_Malloc((1 + nargs + nkwargs) * sizeof(args[0]));
920933
if (stack == NULL) {
921-
PyErr_NoMemory();
934+
_PyErr_NoMemory(tstate);
922935
return NULL;
923936
}
924937

@@ -958,8 +971,8 @@ _PyStack_UnpackDict(PyObject *const *args, Py_ssize_t nargs, PyObject *kwargs,
958971
* because it simplifies the deallocation in the failing case.
959972
* It happens to also make the loop above slightly more efficient. */
960973
if (!keys_are_strings) {
961-
PyErr_SetString(PyExc_TypeError,
962-
"keywords must be strings");
974+
_PyErr_SetString(tstate, PyExc_TypeError,
975+
"keywords must be strings");
963976
_PyStack_UnpackDict_Free(stack, nargs, kwnames);
964977
return NULL;
965978
}

Objects/methodobject.c

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -454,9 +454,11 @@ cfunction_vectorcall_O(
454454
static PyObject *
455455
cfunction_call(PyObject *func, PyObject *args, PyObject *kwargs)
456456
{
457-
assert(!PyErr_Occurred());
458457
assert(kwargs == NULL || PyDict_Check(kwargs));
459458

459+
PyThreadState *tstate = _PyThreadState_GET();
460+
assert(!_PyErr_Occurred(tstate));
461+
460462
int flags = PyCFunction_GET_FLAGS(func);
461463
if (!(flags & METH_VARARGS)) {
462464
/* If this is not a METH_VARARGS function, delegate to vectorcall */
@@ -474,11 +476,12 @@ cfunction_call(PyObject *func, PyObject *args, PyObject *kwargs)
474476
}
475477
else {
476478
if (kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) {
477-
PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments",
478-
((PyCFunctionObject*)func)->m_ml->ml_name);
479+
_PyErr_Format(tstate, PyExc_TypeError,
480+
"%.200s() takes no keyword arguments",
481+
((PyCFunctionObject*)func)->m_ml->ml_name);
479482
return NULL;
480483
}
481484
result = meth(self, args);
482485
}
483-
return _Py_CheckFunctionResult(func, result, NULL);
486+
return _Py_CheckFunctionResult(tstate, func, result, NULL);
484487
}

Objects/typeobject.c

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#include "Python.h"
44
#include "pycore_object.h"
5+
#include "pycore_pyerrors.h"
56
#include "pycore_pystate.h"
67
#include "frameobject.h"
78
#include "structmember.h"
@@ -952,24 +953,24 @@ type_repr(PyTypeObject *type)
952953
static PyObject *
953954
type_call(PyTypeObject *type, PyObject *args, PyObject *kwds)
954955
{
955-
PyObject *obj;
956+
PyThreadState *tstate = _PyThreadState_GET();
956957

957958
if (type->tp_new == NULL) {
958-
PyErr_Format(PyExc_TypeError,
959-
"cannot create '%.100s' instances",
960-
type->tp_name);
959+
_PyErr_Format(tstate, PyExc_TypeError,
960+
"cannot create '%.100s' instances",
961+
type->tp_name);
961962
return NULL;
962963
}
963964

964965
#ifdef Py_DEBUG
965966
/* type_call() must not be called with an exception set,
966967
because it can clear it (directly or indirectly) and so the
967968
caller loses its exception */
968-
assert(!PyErr_Occurred());
969+
assert(!_PyErr_Occurred(tstate));
969970
#endif
970971

971-
obj = type->tp_new(type, args, kwds);
972-
obj = _Py_CheckFunctionResult((PyObject*)type, obj, NULL);
972+
PyObject *obj = type->tp_new(type, args, kwds);
973+
obj = _Py_CheckFunctionResult(tstate, (PyObject*)type, obj, NULL);
973974
if (obj == NULL)
974975
return NULL;
975976

@@ -990,12 +991,12 @@ type_call(PyTypeObject *type, PyObject *args, PyObject *kwds)
990991
if (type->tp_init != NULL) {
991992
int res = type->tp_init(obj, args, kwds);
992993
if (res < 0) {
993-
assert(PyErr_Occurred());
994+
assert(_PyErr_Occurred(tstate));
994995
Py_DECREF(obj);
995996
obj = NULL;
996997
}
997998
else {
998-
assert(!PyErr_Occurred());
999+
assert(!_PyErr_Occurred(tstate));
9991000
}
10001001
}
10011002
return obj;

Python/ceval.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3814,7 +3814,7 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
38143814
f->f_executing = 0;
38153815
tstate->frame = f->f_back;
38163816

3817-
return _Py_CheckFunctionResult(NULL, retval, "PyEval_EvalFrameEx");
3817+
return _Py_CheckFunctionResult(tstate, NULL, retval, "PyEval_EvalFrameEx");
38183818
}
38193819

38203820
static void

Python/errors.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -520,6 +520,21 @@ _PyErr_FormatVFromCause(PyThreadState *tstate, PyObject *exception,
520520
return NULL;
521521
}
522522

523+
PyObject *
524+
_PyErr_FormatFromCauseTstate(PyThreadState *tstate, PyObject *exception,
525+
const char *format, ...)
526+
{
527+
va_list vargs;
528+
#ifdef HAVE_STDARG_PROTOTYPES
529+
va_start(vargs, format);
530+
#else
531+
va_start(vargs);
532+
#endif
533+
_PyErr_FormatVFromCause(tstate, exception, format, vargs);
534+
va_end(vargs);
535+
return NULL;
536+
}
537+
523538
PyObject *
524539
_PyErr_FormatFromCause(PyObject *exception, const char *format, ...)
525540
{

0 commit comments

Comments
 (0)