aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Include/cpython/abstract.h12
-rw-r--r--Include/internal/pycore_pyerrors.h6
-rw-r--r--Objects/call.c81
-rw-r--r--Objects/methodobject.c11
-rw-r--r--Objects/typeobject.c19
-rw-r--r--Python/ceval.c2
-rw-r--r--Python/errors.c15
7 files changed, 94 insertions, 52 deletions
diff --git a/Include/cpython/abstract.h b/Include/cpython/abstract.h
index 04e4a9e7bd2..be37e1971a8 100644
--- a/Include/cpython/abstract.h
+++ b/Include/cpython/abstract.h
@@ -37,9 +37,11 @@ PyAPI_FUNC(PyObject *) _PyStack_AsDict(
40 bytes on the stack. */
#define _PY_FASTCALL_SMALL_STACK 5
-PyAPI_FUNC(PyObject *) _Py_CheckFunctionResult(PyObject *callable,
- PyObject *result,
- const char *where);
+PyAPI_FUNC(PyObject *) _Py_CheckFunctionResult(
+ PyThreadState *tstate,
+ PyObject *callable,
+ PyObject *result,
+ const char *where);
/* === Vectorcall protocol (PEP 590) ============================= */
@@ -98,13 +100,15 @@ _PyObject_Vectorcall(PyObject *callable, PyObject *const *args,
{
assert(kwnames == NULL || PyTuple_Check(kwnames));
assert(args != NULL || PyVectorcall_NARGS(nargsf) == 0);
+
+ PyThreadState *tstate = PyThreadState_GET();
vectorcallfunc func = _PyVectorcall_Function(callable);
if (func == NULL) {
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
return _PyObject_MakeTpCall(callable, args, nargs, kwnames);
}
PyObject *res = func(callable, args, nargsf, kwnames);
- return _Py_CheckFunctionResult(callable, res, NULL);
+ return _Py_CheckFunctionResult(tstate, callable, res, NULL);
}
/* Same as _PyObject_Vectorcall except that keyword arguments are passed as
diff --git a/Include/internal/pycore_pyerrors.h b/Include/internal/pycore_pyerrors.h
index 2efbf4a62f8..edbfdfa597e 100644
--- a/Include/internal/pycore_pyerrors.h
+++ b/Include/internal/pycore_pyerrors.h
@@ -58,6 +58,12 @@ PyAPI_FUNC(void) _PyErr_NormalizeException(
PyObject **val,
PyObject **tb);
+PyAPI_FUNC(PyObject *) _PyErr_FormatFromCauseTstate(
+ PyThreadState *tstate,
+ PyObject *exception,
+ const char *format,
+ ...);
+
#ifdef __cplusplus
}
#endif
diff --git a/Objects/call.c b/Objects/call.c
index b7588b302fb..0d5c41295c2 100644
--- a/Objects/call.c
+++ b/Objects/call.c
@@ -7,8 +7,9 @@
static PyObject *const *
-_PyStack_UnpackDict(PyObject *const *args, Py_ssize_t nargs, PyObject *kwargs,
- PyObject **p_kwnames);
+_PyStack_UnpackDict(PyThreadState *tstate,
+ PyObject *const *args, Py_ssize_t nargs,
+ PyObject *kwargs, PyObject **p_kwnames);
static void
_PyStack_UnpackDict_Free(PyObject *const *stack, Py_ssize_t nargs,
@@ -26,22 +27,23 @@ null_error(void)
PyObject*
-_Py_CheckFunctionResult(PyObject *callable, PyObject *result, const char *where)
+_Py_CheckFunctionResult(PyThreadState *tstate, PyObject *callable,
+ PyObject *result, const char *where)
{
- int err_occurred = (PyErr_Occurred() != NULL);
+ int err_occurred = (_PyErr_Occurred(tstate) != NULL);
assert((callable != NULL) ^ (where != NULL));
if (result == NULL) {
if (!err_occurred) {
if (callable)
- PyErr_Format(PyExc_SystemError,
- "%R returned NULL without setting an error",
- callable);
+ _PyErr_Format(tstate, PyExc_SystemError,
+ "%R returned NULL without setting an error",
+ callable);
else
- PyErr_Format(PyExc_SystemError,
- "%s returned NULL without setting an error",
- where);
+ _PyErr_Format(tstate, PyExc_SystemError,
+ "%s returned NULL without setting an error",
+ where);
#ifdef Py_DEBUG
/* Ensure that the bug is caught in debug mode */
Py_FatalError("a function returned NULL without setting an error");
@@ -54,14 +56,14 @@ _Py_CheckFunctionResult(PyObject *callable, PyObject *result, const char *where)
Py_DECREF(result);
if (callable) {
- _PyErr_FormatFromCause(PyExc_SystemError,
- "%R returned a result with an error set",
- callable);
+ _PyErr_FormatFromCauseTstate(
+ tstate, PyExc_SystemError,
+ "%R returned a result with an error set", callable);
}
else {
- _PyErr_FormatFromCause(PyExc_SystemError,
- "%s returned a result with an error set",
- where);
+ _PyErr_FormatFromCauseTstate(
+ tstate, PyExc_SystemError,
+ "%s returned a result with an error set", where);
}
#ifdef Py_DEBUG
/* Ensure that the bug is caught in debug mode */
@@ -88,11 +90,13 @@ PyObject *
_PyObject_FastCallDict(PyObject *callable, PyObject *const *args,
size_t nargsf, PyObject *kwargs)
{
+ assert(callable != NULL);
+
+ PyThreadState *tstate = _PyThreadState_GET();
/* _PyObject_FastCallDict() 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(callable != NULL);
+ assert(!_PyErr_Occurred(tstate));
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
assert(nargs >= 0);
@@ -112,7 +116,9 @@ _PyObject_FastCallDict(PyObject *callable, PyObject *const *args,
else {
PyObject *kwnames;
PyObject *const *newargs;
- newargs = _PyStack_UnpackDict(args, nargs, kwargs, &kwnames);
+ newargs = _PyStack_UnpackDict(tstate,
+ args, nargs,
+ kwargs, &kwnames);
if (newargs == NULL) {
return NULL;
}
@@ -120,7 +126,7 @@ _PyObject_FastCallDict(PyObject *callable, PyObject *const *args,
nargs | PY_VECTORCALL_ARGUMENTS_OFFSET, kwnames);
_PyStack_UnpackDict_Free(newargs, nargs, kwnames);
}
- return _Py_CheckFunctionResult(callable, res, NULL);
+ return _Py_CheckFunctionResult(tstate, callable, res, NULL);
}
@@ -177,7 +183,7 @@ _PyObject_MakeTpCall(PyObject *callable, PyObject *const *args, Py_ssize_t nargs
Py_DECREF(kwdict);
}
- result = _Py_CheckFunctionResult(callable, result, NULL);
+ result = _Py_CheckFunctionResult(tstate, callable, result, NULL);
return result;
}
@@ -185,18 +191,22 @@ _PyObject_MakeTpCall(PyObject *callable, PyObject *const *args, Py_ssize_t nargs
PyObject *
PyVectorcall_Call(PyObject *callable, PyObject *tuple, PyObject *kwargs)
{
+ PyThreadState *tstate = _PyThreadState_GET();
+
/* get vectorcallfunc as in _PyVectorcall_Function, but without
* the _Py_TPFLAGS_HAVE_VECTORCALL check */
Py_ssize_t offset = Py_TYPE(callable)->tp_vectorcall_offset;
if (offset <= 0) {
- PyErr_Format(PyExc_TypeError, "'%.200s' object does not support vectorcall",
- Py_TYPE(callable)->tp_name);
+ _PyErr_Format(tstate, PyExc_TypeError,
+ "'%.200s' object does not support vectorcall",
+ Py_TYPE(callable)->tp_name);
return NULL;
}
vectorcallfunc func = *(vectorcallfunc *)(((char *)callable) + offset);
if (func == NULL) {
- PyErr_Format(PyExc_TypeError, "'%.200s' object does not support vectorcall",
- Py_TYPE(callable)->tp_name);
+ _PyErr_Format(tstate, PyExc_TypeError,
+ "'%.200s' object does not support vectorcall",
+ Py_TYPE(callable)->tp_name);
return NULL;
}
@@ -210,14 +220,16 @@ PyVectorcall_Call(PyObject *callable, PyObject *tuple, PyObject *kwargs)
/* Convert arguments & call */
PyObject *const *args;
PyObject *kwnames;
- args = _PyStack_UnpackDict(_PyTuple_ITEMS(tuple), nargs, kwargs, &kwnames);
+ args = _PyStack_UnpackDict(tstate,
+ _PyTuple_ITEMS(tuple), nargs,
+ kwargs, &kwnames);
if (args == NULL) {
return NULL;
}
PyObject *result = func(callable, args,
nargs | PY_VECTORCALL_ARGUMENTS_OFFSET, kwnames);
_PyStack_UnpackDict_Free(args, nargs, kwnames);
- return _Py_CheckFunctionResult(callable, result, NULL);
+ return _Py_CheckFunctionResult(tstate, callable, result, NULL);
}
@@ -255,7 +267,7 @@ PyObject_Call(PyObject *callable, PyObject *args, PyObject *kwargs)
_Py_LeaveRecursiveCall(tstate);
- return _Py_CheckFunctionResult(callable, result, NULL);
+ return _Py_CheckFunctionResult(tstate, callable, result, NULL);
}
}
@@ -898,8 +910,9 @@ _PyStack_AsDict(PyObject *const *values, PyObject *kwnames)
When done, you must call _PyStack_UnpackDict_Free(stack, nargs, kwnames) */
static PyObject *const *
-_PyStack_UnpackDict(PyObject *const *args, Py_ssize_t nargs, PyObject *kwargs,
- PyObject **p_kwnames)
+_PyStack_UnpackDict(PyThreadState *tstate,
+ PyObject *const *args, Py_ssize_t nargs,
+ PyObject *kwargs, PyObject **p_kwnames)
{
assert(nargs >= 0);
assert(kwargs != NULL);
@@ -911,14 +924,14 @@ _PyStack_UnpackDict(PyObject *const *args, Py_ssize_t nargs, PyObject *kwargs,
* non-negative signed integers, so their difference fits in the type. */
Py_ssize_t maxnargs = PY_SSIZE_T_MAX / sizeof(args[0]) - 1;
if (nargs > maxnargs - nkwargs) {
- PyErr_NoMemory();
+ _PyErr_NoMemory(tstate);
return NULL;
}
/* Add 1 to support PY_VECTORCALL_ARGUMENTS_OFFSET */
PyObject **stack = PyMem_Malloc((1 + nargs + nkwargs) * sizeof(args[0]));
if (stack == NULL) {
- PyErr_NoMemory();
+ _PyErr_NoMemory(tstate);
return NULL;
}
@@ -958,8 +971,8 @@ _PyStack_UnpackDict(PyObject *const *args, Py_ssize_t nargs, PyObject *kwargs,
* because it simplifies the deallocation in the failing case.
* It happens to also make the loop above slightly more efficient. */
if (!keys_are_strings) {
- PyErr_SetString(PyExc_TypeError,
- "keywords must be strings");
+ _PyErr_SetString(tstate, PyExc_TypeError,
+ "keywords must be strings");
_PyStack_UnpackDict_Free(stack, nargs, kwnames);
return NULL;
}
diff --git a/Objects/methodobject.c b/Objects/methodobject.c
index 3ce15604b90..c780904d7f9 100644
--- a/Objects/methodobject.c
+++ b/Objects/methodobject.c
@@ -454,9 +454,11 @@ cfunction_vectorcall_O(
static PyObject *
cfunction_call(PyObject *func, PyObject *args, PyObject *kwargs)
{
- assert(!PyErr_Occurred());
assert(kwargs == NULL || PyDict_Check(kwargs));
+ PyThreadState *tstate = _PyThreadState_GET();
+ assert(!_PyErr_Occurred(tstate));
+
int flags = PyCFunction_GET_FLAGS(func);
if (!(flags & METH_VARARGS)) {
/* If this is not a METH_VARARGS function, delegate to vectorcall */
@@ -474,11 +476,12 @@ cfunction_call(PyObject *func, PyObject *args, PyObject *kwargs)
}
else {
if (kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) {
- PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments",
- ((PyCFunctionObject*)func)->m_ml->ml_name);
+ _PyErr_Format(tstate, PyExc_TypeError,
+ "%.200s() takes no keyword arguments",
+ ((PyCFunctionObject*)func)->m_ml->ml_name);
return NULL;
}
result = meth(self, args);
}
- return _Py_CheckFunctionResult(func, result, NULL);
+ return _Py_CheckFunctionResult(tstate, func, result, NULL);
}
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index 890246e14a6..0e1cb7b7aeb 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -2,6 +2,7 @@
#include "Python.h"
#include "pycore_object.h"
+#include "pycore_pyerrors.h"
#include "pycore_pystate.h"
#include "frameobject.h"
#include "structmember.h"
@@ -952,12 +953,12 @@ type_repr(PyTypeObject *type)
static PyObject *
type_call(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
- PyObject *obj;
+ PyThreadState *tstate = _PyThreadState_GET();
if (type->tp_new == NULL) {
- PyErr_Format(PyExc_TypeError,
- "cannot create '%.100s' instances",
- type->tp_name);
+ _PyErr_Format(tstate, PyExc_TypeError,
+ "cannot create '%.100s' instances",
+ type->tp_name);
return NULL;
}
@@ -965,11 +966,11 @@ type_call(PyTypeObject *type, PyObject *args, PyObject *kwds)
/* type_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));
#endif
- obj = type->tp_new(type, args, kwds);
- obj = _Py_CheckFunctionResult((PyObject*)type, obj, NULL);
+ PyObject *obj = type->tp_new(type, args, kwds);
+ obj = _Py_CheckFunctionResult(tstate, (PyObject*)type, obj, NULL);
if (obj == NULL)
return NULL;
@@ -990,12 +991,12 @@ type_call(PyTypeObject *type, PyObject *args, PyObject *kwds)
if (type->tp_init != NULL) {
int res = type->tp_init(obj, args, kwds);
if (res < 0) {
- assert(PyErr_Occurred());
+ assert(_PyErr_Occurred(tstate));
Py_DECREF(obj);
obj = NULL;
}
else {
- assert(!PyErr_Occurred());
+ assert(!_PyErr_Occurred(tstate));
}
}
return obj;
diff --git a/Python/ceval.c b/Python/ceval.c
index a01fa35dca2..9019c785080 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -3814,7 +3814,7 @@ exit_eval_frame:
f->f_executing = 0;
tstate->frame = f->f_back;
- return _Py_CheckFunctionResult(NULL, retval, "PyEval_EvalFrameEx");
+ return _Py_CheckFunctionResult(tstate, NULL, retval, "PyEval_EvalFrameEx");
}
static void
diff --git a/Python/errors.c b/Python/errors.c
index b935341636f..9658afeb9f7 100644
--- a/Python/errors.c
+++ b/Python/errors.c
@@ -521,6 +521,21 @@ _PyErr_FormatVFromCause(PyThreadState *tstate, PyObject *exception,
}
PyObject *
+_PyErr_FormatFromCauseTstate(PyThreadState *tstate, PyObject *exception,
+ const char *format, ...)
+{
+ va_list vargs;
+#ifdef HAVE_STDARG_PROTOTYPES
+ va_start(vargs, format);
+#else
+ va_start(vargs);
+#endif
+ _PyErr_FormatVFromCause(tstate, exception, format, vargs);
+ va_end(vargs);
+ return NULL;
+}
+
+PyObject *
_PyErr_FormatFromCause(PyObject *exception, const char *format, ...)
{
PyThreadState *tstate = _PyThreadState_GET();