mirror of https://github.com/python/cpython
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, ...)
This commit is contained in:
parent
be434dc038
commit
1726909094
|
@ -37,9 +37,11 @@ PyAPI_FUNC(PyObject *) _PyStack_AsDict(
|
||||||
40 bytes on the stack. */
|
40 bytes on the stack. */
|
||||||
#define _PY_FASTCALL_SMALL_STACK 5
|
#define _PY_FASTCALL_SMALL_STACK 5
|
||||||
|
|
||||||
PyAPI_FUNC(PyObject *) _Py_CheckFunctionResult(PyObject *callable,
|
PyAPI_FUNC(PyObject *) _Py_CheckFunctionResult(
|
||||||
PyObject *result,
|
PyThreadState *tstate,
|
||||||
const char *where);
|
PyObject *callable,
|
||||||
|
PyObject *result,
|
||||||
|
const char *where);
|
||||||
|
|
||||||
/* === Vectorcall protocol (PEP 590) ============================= */
|
/* === Vectorcall protocol (PEP 590) ============================= */
|
||||||
|
|
||||||
|
@ -98,13 +100,15 @@ _PyObject_Vectorcall(PyObject *callable, PyObject *const *args,
|
||||||
{
|
{
|
||||||
assert(kwnames == NULL || PyTuple_Check(kwnames));
|
assert(kwnames == NULL || PyTuple_Check(kwnames));
|
||||||
assert(args != NULL || PyVectorcall_NARGS(nargsf) == 0);
|
assert(args != NULL || PyVectorcall_NARGS(nargsf) == 0);
|
||||||
|
|
||||||
|
PyThreadState *tstate = PyThreadState_GET();
|
||||||
vectorcallfunc func = _PyVectorcall_Function(callable);
|
vectorcallfunc func = _PyVectorcall_Function(callable);
|
||||||
if (func == NULL) {
|
if (func == NULL) {
|
||||||
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
|
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
|
||||||
return _PyObject_MakeTpCall(callable, args, nargs, kwnames);
|
return _PyObject_MakeTpCall(callable, args, nargs, kwnames);
|
||||||
}
|
}
|
||||||
PyObject *res = func(callable, args, nargsf, 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
|
/* Same as _PyObject_Vectorcall except that keyword arguments are passed as
|
||||||
|
|
|
@ -58,6 +58,12 @@ PyAPI_FUNC(void) _PyErr_NormalizeException(
|
||||||
PyObject **val,
|
PyObject **val,
|
||||||
PyObject **tb);
|
PyObject **tb);
|
||||||
|
|
||||||
|
PyAPI_FUNC(PyObject *) _PyErr_FormatFromCauseTstate(
|
||||||
|
PyThreadState *tstate,
|
||||||
|
PyObject *exception,
|
||||||
|
const char *format,
|
||||||
|
...);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -7,8 +7,9 @@
|
||||||
|
|
||||||
|
|
||||||
static PyObject *const *
|
static PyObject *const *
|
||||||
_PyStack_UnpackDict(PyObject *const *args, Py_ssize_t nargs, PyObject *kwargs,
|
_PyStack_UnpackDict(PyThreadState *tstate,
|
||||||
PyObject **p_kwnames);
|
PyObject *const *args, Py_ssize_t nargs,
|
||||||
|
PyObject *kwargs, PyObject **p_kwnames);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_PyStack_UnpackDict_Free(PyObject *const *stack, Py_ssize_t nargs,
|
_PyStack_UnpackDict_Free(PyObject *const *stack, Py_ssize_t nargs,
|
||||||
|
@ -26,22 +27,23 @@ null_error(void)
|
||||||
|
|
||||||
|
|
||||||
PyObject*
|
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));
|
assert((callable != NULL) ^ (where != NULL));
|
||||||
|
|
||||||
if (result == NULL) {
|
if (result == NULL) {
|
||||||
if (!err_occurred) {
|
if (!err_occurred) {
|
||||||
if (callable)
|
if (callable)
|
||||||
PyErr_Format(PyExc_SystemError,
|
_PyErr_Format(tstate, PyExc_SystemError,
|
||||||
"%R returned NULL without setting an error",
|
"%R returned NULL without setting an error",
|
||||||
callable);
|
callable);
|
||||||
else
|
else
|
||||||
PyErr_Format(PyExc_SystemError,
|
_PyErr_Format(tstate, PyExc_SystemError,
|
||||||
"%s returned NULL without setting an error",
|
"%s returned NULL without setting an error",
|
||||||
where);
|
where);
|
||||||
#ifdef Py_DEBUG
|
#ifdef Py_DEBUG
|
||||||
/* Ensure that the bug is caught in debug mode */
|
/* Ensure that the bug is caught in debug mode */
|
||||||
Py_FatalError("a function returned NULL without setting an error");
|
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);
|
Py_DECREF(result);
|
||||||
|
|
||||||
if (callable) {
|
if (callable) {
|
||||||
_PyErr_FormatFromCause(PyExc_SystemError,
|
_PyErr_FormatFromCauseTstate(
|
||||||
"%R returned a result with an error set",
|
tstate, PyExc_SystemError,
|
||||||
callable);
|
"%R returned a result with an error set", callable);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
_PyErr_FormatFromCause(PyExc_SystemError,
|
_PyErr_FormatFromCauseTstate(
|
||||||
"%s returned a result with an error set",
|
tstate, PyExc_SystemError,
|
||||||
where);
|
"%s returned a result with an error set", where);
|
||||||
}
|
}
|
||||||
#ifdef Py_DEBUG
|
#ifdef Py_DEBUG
|
||||||
/* Ensure that the bug is caught in debug mode */
|
/* Ensure that the bug is caught in debug mode */
|
||||||
|
@ -88,11 +90,13 @@ PyObject *
|
||||||
_PyObject_FastCallDict(PyObject *callable, PyObject *const *args,
|
_PyObject_FastCallDict(PyObject *callable, PyObject *const *args,
|
||||||
size_t nargsf, PyObject *kwargs)
|
size_t nargsf, PyObject *kwargs)
|
||||||
{
|
{
|
||||||
|
assert(callable != NULL);
|
||||||
|
|
||||||
|
PyThreadState *tstate = _PyThreadState_GET();
|
||||||
/* _PyObject_FastCallDict() must not be called with an exception set,
|
/* _PyObject_FastCallDict() 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(callable != NULL);
|
|
||||||
|
|
||||||
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
|
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
|
||||||
assert(nargs >= 0);
|
assert(nargs >= 0);
|
||||||
|
@ -112,7 +116,9 @@ _PyObject_FastCallDict(PyObject *callable, PyObject *const *args,
|
||||||
else {
|
else {
|
||||||
PyObject *kwnames;
|
PyObject *kwnames;
|
||||||
PyObject *const *newargs;
|
PyObject *const *newargs;
|
||||||
newargs = _PyStack_UnpackDict(args, nargs, kwargs, &kwnames);
|
newargs = _PyStack_UnpackDict(tstate,
|
||||||
|
args, nargs,
|
||||||
|
kwargs, &kwnames);
|
||||||
if (newargs == NULL) {
|
if (newargs == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -120,7 +126,7 @@ _PyObject_FastCallDict(PyObject *callable, PyObject *const *args,
|
||||||
nargs | PY_VECTORCALL_ARGUMENTS_OFFSET, kwnames);
|
nargs | PY_VECTORCALL_ARGUMENTS_OFFSET, kwnames);
|
||||||
_PyStack_UnpackDict_Free(newargs, nargs, 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);
|
Py_DECREF(kwdict);
|
||||||
}
|
}
|
||||||
|
|
||||||
result = _Py_CheckFunctionResult(callable, result, NULL);
|
result = _Py_CheckFunctionResult(tstate, callable, result, NULL);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,18 +191,22 @@ _PyObject_MakeTpCall(PyObject *callable, PyObject *const *args, Py_ssize_t nargs
|
||||||
PyObject *
|
PyObject *
|
||||||
PyVectorcall_Call(PyObject *callable, PyObject *tuple, PyObject *kwargs)
|
PyVectorcall_Call(PyObject *callable, PyObject *tuple, PyObject *kwargs)
|
||||||
{
|
{
|
||||||
|
PyThreadState *tstate = _PyThreadState_GET();
|
||||||
|
|
||||||
/* get vectorcallfunc as in _PyVectorcall_Function, but without
|
/* get vectorcallfunc as in _PyVectorcall_Function, but without
|
||||||
* the _Py_TPFLAGS_HAVE_VECTORCALL check */
|
* the _Py_TPFLAGS_HAVE_VECTORCALL check */
|
||||||
Py_ssize_t offset = Py_TYPE(callable)->tp_vectorcall_offset;
|
Py_ssize_t offset = Py_TYPE(callable)->tp_vectorcall_offset;
|
||||||
if (offset <= 0) {
|
if (offset <= 0) {
|
||||||
PyErr_Format(PyExc_TypeError, "'%.200s' object does not support vectorcall",
|
_PyErr_Format(tstate, PyExc_TypeError,
|
||||||
Py_TYPE(callable)->tp_name);
|
"'%.200s' object does not support vectorcall",
|
||||||
|
Py_TYPE(callable)->tp_name);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
vectorcallfunc func = *(vectorcallfunc *)(((char *)callable) + offset);
|
vectorcallfunc func = *(vectorcallfunc *)(((char *)callable) + offset);
|
||||||
if (func == NULL) {
|
if (func == NULL) {
|
||||||
PyErr_Format(PyExc_TypeError, "'%.200s' object does not support vectorcall",
|
_PyErr_Format(tstate, PyExc_TypeError,
|
||||||
Py_TYPE(callable)->tp_name);
|
"'%.200s' object does not support vectorcall",
|
||||||
|
Py_TYPE(callable)->tp_name);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -210,14 +220,16 @@ PyVectorcall_Call(PyObject *callable, PyObject *tuple, PyObject *kwargs)
|
||||||
/* Convert arguments & call */
|
/* Convert arguments & call */
|
||||||
PyObject *const *args;
|
PyObject *const *args;
|
||||||
PyObject *kwnames;
|
PyObject *kwnames;
|
||||||
args = _PyStack_UnpackDict(_PyTuple_ITEMS(tuple), nargs, kwargs, &kwnames);
|
args = _PyStack_UnpackDict(tstate,
|
||||||
|
_PyTuple_ITEMS(tuple), nargs,
|
||||||
|
kwargs, &kwnames);
|
||||||
if (args == NULL) {
|
if (args == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
PyObject *result = func(callable, args,
|
PyObject *result = func(callable, args,
|
||||||
nargs | PY_VECTORCALL_ARGUMENTS_OFFSET, kwnames);
|
nargs | PY_VECTORCALL_ARGUMENTS_OFFSET, kwnames);
|
||||||
_PyStack_UnpackDict_Free(args, nargs, 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);
|
_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) */
|
When done, you must call _PyStack_UnpackDict_Free(stack, nargs, kwnames) */
|
||||||
static PyObject *const *
|
static PyObject *const *
|
||||||
_PyStack_UnpackDict(PyObject *const *args, Py_ssize_t nargs, PyObject *kwargs,
|
_PyStack_UnpackDict(PyThreadState *tstate,
|
||||||
PyObject **p_kwnames)
|
PyObject *const *args, Py_ssize_t nargs,
|
||||||
|
PyObject *kwargs, PyObject **p_kwnames)
|
||||||
{
|
{
|
||||||
assert(nargs >= 0);
|
assert(nargs >= 0);
|
||||||
assert(kwargs != NULL);
|
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. */
|
* non-negative signed integers, so their difference fits in the type. */
|
||||||
Py_ssize_t maxnargs = PY_SSIZE_T_MAX / sizeof(args[0]) - 1;
|
Py_ssize_t maxnargs = PY_SSIZE_T_MAX / sizeof(args[0]) - 1;
|
||||||
if (nargs > maxnargs - nkwargs) {
|
if (nargs > maxnargs - nkwargs) {
|
||||||
PyErr_NoMemory();
|
_PyErr_NoMemory(tstate);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add 1 to support PY_VECTORCALL_ARGUMENTS_OFFSET */
|
/* Add 1 to support PY_VECTORCALL_ARGUMENTS_OFFSET */
|
||||||
PyObject **stack = PyMem_Malloc((1 + nargs + nkwargs) * sizeof(args[0]));
|
PyObject **stack = PyMem_Malloc((1 + nargs + nkwargs) * sizeof(args[0]));
|
||||||
if (stack == NULL) {
|
if (stack == NULL) {
|
||||||
PyErr_NoMemory();
|
_PyErr_NoMemory(tstate);
|
||||||
return NULL;
|
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.
|
* because it simplifies the deallocation in the failing case.
|
||||||
* It happens to also make the loop above slightly more efficient. */
|
* It happens to also make the loop above slightly more efficient. */
|
||||||
if (!keys_are_strings) {
|
if (!keys_are_strings) {
|
||||||
PyErr_SetString(PyExc_TypeError,
|
_PyErr_SetString(tstate, PyExc_TypeError,
|
||||||
"keywords must be strings");
|
"keywords must be strings");
|
||||||
_PyStack_UnpackDict_Free(stack, nargs, kwnames);
|
_PyStack_UnpackDict_Free(stack, nargs, kwnames);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -454,9 +454,11 @@ cfunction_vectorcall_O(
|
||||||
static PyObject *
|
static PyObject *
|
||||||
cfunction_call(PyObject *func, PyObject *args, PyObject *kwargs)
|
cfunction_call(PyObject *func, PyObject *args, PyObject *kwargs)
|
||||||
{
|
{
|
||||||
assert(!PyErr_Occurred());
|
|
||||||
assert(kwargs == NULL || PyDict_Check(kwargs));
|
assert(kwargs == NULL || PyDict_Check(kwargs));
|
||||||
|
|
||||||
|
PyThreadState *tstate = _PyThreadState_GET();
|
||||||
|
assert(!_PyErr_Occurred(tstate));
|
||||||
|
|
||||||
int flags = PyCFunction_GET_FLAGS(func);
|
int flags = PyCFunction_GET_FLAGS(func);
|
||||||
if (!(flags & METH_VARARGS)) {
|
if (!(flags & METH_VARARGS)) {
|
||||||
/* If this is not a METH_VARARGS function, delegate to vectorcall */
|
/* If this is not a METH_VARARGS function, delegate to vectorcall */
|
||||||
|
@ -474,11 +476,12 @@ cfunction_call(PyObject *func, PyObject *args, PyObject *kwargs)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) {
|
if (kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) {
|
||||||
PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments",
|
_PyErr_Format(tstate, PyExc_TypeError,
|
||||||
((PyCFunctionObject*)func)->m_ml->ml_name);
|
"%.200s() takes no keyword arguments",
|
||||||
|
((PyCFunctionObject*)func)->m_ml->ml_name);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
result = meth(self, args);
|
result = meth(self, args);
|
||||||
}
|
}
|
||||||
return _Py_CheckFunctionResult(func, result, NULL);
|
return _Py_CheckFunctionResult(tstate, func, result, NULL);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#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 "frameobject.h"
|
#include "frameobject.h"
|
||||||
#include "structmember.h"
|
#include "structmember.h"
|
||||||
|
@ -952,12 +953,12 @@ type_repr(PyTypeObject *type)
|
||||||
static PyObject *
|
static PyObject *
|
||||||
type_call(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
type_call(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||||
{
|
{
|
||||||
PyObject *obj;
|
PyThreadState *tstate = _PyThreadState_GET();
|
||||||
|
|
||||||
if (type->tp_new == NULL) {
|
if (type->tp_new == NULL) {
|
||||||
PyErr_Format(PyExc_TypeError,
|
_PyErr_Format(tstate, PyExc_TypeError,
|
||||||
"cannot create '%.100s' instances",
|
"cannot create '%.100s' instances",
|
||||||
type->tp_name);
|
type->tp_name);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -965,11 +966,11 @@ type_call(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||||
/* type_call() must not be called with an exception set,
|
/* type_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));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
obj = type->tp_new(type, args, kwds);
|
PyObject *obj = type->tp_new(type, args, kwds);
|
||||||
obj = _Py_CheckFunctionResult((PyObject*)type, obj, NULL);
|
obj = _Py_CheckFunctionResult(tstate, (PyObject*)type, obj, NULL);
|
||||||
if (obj == NULL)
|
if (obj == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -990,12 +991,12 @@ type_call(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||||
if (type->tp_init != NULL) {
|
if (type->tp_init != NULL) {
|
||||||
int res = type->tp_init(obj, args, kwds);
|
int res = type->tp_init(obj, args, kwds);
|
||||||
if (res < 0) {
|
if (res < 0) {
|
||||||
assert(PyErr_Occurred());
|
assert(_PyErr_Occurred(tstate));
|
||||||
Py_DECREF(obj);
|
Py_DECREF(obj);
|
||||||
obj = NULL;
|
obj = NULL;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
assert(!PyErr_Occurred());
|
assert(!_PyErr_Occurred(tstate));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return obj;
|
return obj;
|
||||||
|
|
|
@ -3814,7 +3814,7 @@ exit_eval_frame:
|
||||||
f->f_executing = 0;
|
f->f_executing = 0;
|
||||||
tstate->frame = f->f_back;
|
tstate->frame = f->f_back;
|
||||||
|
|
||||||
return _Py_CheckFunctionResult(NULL, retval, "PyEval_EvalFrameEx");
|
return _Py_CheckFunctionResult(tstate, NULL, retval, "PyEval_EvalFrameEx");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
|
@ -520,6 +520,21 @@ _PyErr_FormatVFromCause(PyThreadState *tstate, PyObject *exception,
|
||||||
return NULL;
|
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 *
|
PyObject *
|
||||||
_PyErr_FormatFromCause(PyObject *exception, const char *format, ...)
|
_PyErr_FormatFromCause(PyObject *exception, const char *format, ...)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue