[Python-checkins] bpo-38644: Pass tstate to _Py_CheckFunctionResult() (GH-17050)

Victor Stinner webhook-mailer at python.org
Mon Nov 4 19:22:16 EST 2019


https://github.com/python/cpython/commit/17269090940aa20f6079a6b9f27ae319f8cdae14
commit: 17269090940aa20f6079a6b9f27ae319f8cdae14
branch: master
author: Victor Stinner <vstinner at python.org>
committer: GitHub <noreply at github.com>
date: 2019-11-05T01:22:12+01:00
summary:

bpo-38644: Pass tstate to _Py_CheckFunctionResult() (GH-17050)

* Add tstate parameter to _Py_CheckFunctionResult()
* Add _PyErr_FormatFromCauseTstate()
* Replace PyErr_XXX(...) with _PyErr_XXX(state, ...)

files:
M Include/cpython/abstract.h
M Include/internal/pycore_pyerrors.h
M Objects/call.c
M Objects/methodobject.c
M Objects/typeobject.c
M Python/ceval.c
M Python/errors.c

diff --git a/Include/cpython/abstract.h b/Include/cpython/abstract.h
index 04e4a9e7bd277..be37e1971a814 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 2efbf4a62f817..edbfdfa597e1f 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 b7588b302fb7d..0d5c41295c29c 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 3ce15604b90f1..c780904d7f9aa 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 890246e14a695..0e1cb7b7aeb36 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 a01fa35dca2d0..9019c785080a3 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -3814,7 +3814,7 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
     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 b935341636f78..9658afeb9f773 100644
--- a/Python/errors.c
+++ b/Python/errors.c
@@ -520,6 +520,21 @@ _PyErr_FormatVFromCause(PyThreadState *tstate, PyObject *exception,
     return NULL;
 }
 
+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, ...)
 {



More information about the Python-checkins mailing list