diff options
author | Victor Stinner <vstinner@python.org> | 2021-01-27 16:39:16 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-01-27 16:39:16 (GMT) |
commit | c9b8e9c421b57acdcaf24fab0c93bc29b3ef7c67 (patch) | |
tree | f174c17b926bd968bf19ddd330524bda46e7aa8e /Objects | |
parent | eeb701adc0fc29ba803fddf133d917ff45639a00 (diff) | |
download | cpython-c9b8e9c421b57acdcaf24fab0c93bc29b3ef7c67.zip cpython-c9b8e9c421b57acdcaf24fab0c93bc29b3ef7c67.tar.gz cpython-c9b8e9c421b57acdcaf24fab0c93bc29b3ef7c67.tar.bz2 |
bpo-42979: Enhance abstract.c assertions checking slot result (GH-24352)
* bpo-42979: Enhance abstract.c assertions checking slot result
Add _Py_CheckSlotResult() function which fails with a fatal error if
a slot function succeeded with an exception set or failed with no
exception set: write the slot name, the type name and the current
exception (if an exception is set).
Diffstat (limited to 'Objects')
-rw-r--r-- | Objects/abstract.c | 17 | ||||
-rw-r--r-- | Objects/call.c | 36 |
2 files changed, 39 insertions, 14 deletions
diff --git a/Objects/abstract.c b/Objects/abstract.c index 44ed5b3..cc452ea 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -1,11 +1,12 @@ /* Abstract Object Interface (many thanks to Jim Fulton) */ #include "Python.h" -#include "pycore_unionobject.h" // _Py_UnionType && _Py_Union() #include "pycore_abstract.h" // _PyIndex_Check() #include "pycore_ceval.h" // _Py_EnterRecursiveCall() +#include "pycore_object.h" // _Py_CheckSlotResult() #include "pycore_pyerrors.h" // _PyErr_Occurred() #include "pycore_pystate.h" // _PyThreadState_GET() +#include "pycore_unionobject.h" // _Py_UnionType && _Py_Union() #include <ctype.h> #include <stddef.h> // offsetof() #include "longintrepr.h" @@ -61,7 +62,7 @@ PyObject_Size(PyObject *o) m = Py_TYPE(o)->tp_as_sequence; if (m && m->sq_length) { Py_ssize_t len = m->sq_length(o); - assert(len >= 0 || PyErr_Occurred()); + assert(_Py_CheckSlotResult(o, "__len__", len >= 0)); return len; } @@ -160,7 +161,7 @@ PyObject_GetItem(PyObject *o, PyObject *key) m = Py_TYPE(o)->tp_as_mapping; if (m && m->mp_subscript) { PyObject *item = m->mp_subscript(o, key); - assert((item != NULL) ^ (PyErr_Occurred() != NULL)); + assert(_Py_CheckSlotResult(o, "__getitem__", item != NULL)); return item; } @@ -1564,7 +1565,7 @@ PySequence_Size(PyObject *s) m = Py_TYPE(s)->tp_as_sequence; if (m && m->sq_length) { Py_ssize_t len = m->sq_length(s); - assert(len >= 0 || PyErr_Occurred()); + assert(_Py_CheckSlotResult(s, "__len__", len >= 0)); return len; } @@ -1708,8 +1709,8 @@ PySequence_GetItem(PyObject *s, Py_ssize_t i) if (i < 0) { if (m->sq_length) { Py_ssize_t l = (*m->sq_length)(s); + assert(_Py_CheckSlotResult(s, "__len__", l >= 0)); if (l < 0) { - assert(PyErr_Occurred()); return NULL; } i += l; @@ -1762,8 +1763,8 @@ PySequence_SetItem(PyObject *s, Py_ssize_t i, PyObject *o) if (i < 0) { if (m->sq_length) { Py_ssize_t l = (*m->sq_length)(s); + assert(_Py_CheckSlotResult(s, "__len__", l >= 0)); if (l < 0) { - assert(PyErr_Occurred()); return -1; } i += l; @@ -1795,8 +1796,8 @@ PySequence_DelItem(PyObject *s, Py_ssize_t i) if (i < 0) { if (m->sq_length) { Py_ssize_t l = (*m->sq_length)(s); + assert(_Py_CheckSlotResult(s, "__len__", l >= 0)); if (l < 0) { - assert(PyErr_Occurred()); return -1; } i += l; @@ -2145,7 +2146,7 @@ PyMapping_Size(PyObject *o) m = Py_TYPE(o)->tp_as_mapping; if (m && m->mp_length) { Py_ssize_t len = m->mp_length(o); - assert(len >= 0 || PyErr_Occurred()); + assert(_Py_CheckSlotResult(o, "__len__", len >= 0)); return len; } diff --git a/Objects/call.c b/Objects/call.c index 35b06a9..1fb85ef 100644 --- a/Objects/call.c +++ b/Objects/call.c @@ -39,16 +39,16 @@ _Py_CheckFunctionResult(PyThreadState *tstate, PyObject *callable, if (!_PyErr_Occurred(tstate)) { if (callable) _PyErr_Format(tstate, PyExc_SystemError, - "%R returned NULL without setting an error", + "%R returned NULL without setting an exception", callable); else _PyErr_Format(tstate, PyExc_SystemError, - "%s returned NULL without setting an error", + "%s returned NULL without setting an exception", where); #ifdef Py_DEBUG /* Ensure that the bug is caught in debug mode. Py_FatalError() logs the SystemError exception raised above. */ - Py_FatalError("a function returned NULL without setting an error"); + Py_FatalError("a function returned NULL without setting an exception"); #endif return NULL; } @@ -60,17 +60,17 @@ _Py_CheckFunctionResult(PyThreadState *tstate, PyObject *callable, if (callable) { _PyErr_FormatFromCauseTstate( tstate, PyExc_SystemError, - "%R returned a result with an error set", callable); + "%R returned a result with an exception set", callable); } else { _PyErr_FormatFromCauseTstate( tstate, PyExc_SystemError, - "%s returned a result with an error set", where); + "%s returned a result with an exception set", where); } #ifdef Py_DEBUG /* Ensure that the bug is caught in debug mode. Py_FatalError() logs the SystemError exception raised above. */ - Py_FatalError("a function returned a result with an error set"); + Py_FatalError("a function returned a result with an exception set"); #endif return NULL; } @@ -79,6 +79,30 @@ _Py_CheckFunctionResult(PyThreadState *tstate, PyObject *callable, } +int +_Py_CheckSlotResult(PyObject *obj, const char *slot_name, int success) +{ + PyThreadState *tstate = _PyThreadState_GET(); + if (!success) { + if (!_PyErr_Occurred(tstate)) { + _Py_FatalErrorFormat(__func__, + "Slot %s of type %s failed " + "without setting an exception", + slot_name, Py_TYPE(obj)->tp_name); + } + } + else { + if (_PyErr_Occurred(tstate)) { + _Py_FatalErrorFormat(__func__, + "Slot %s of type %s succeeded " + "with an exception set", + slot_name, Py_TYPE(obj)->tp_name); + } + } + return 1; +} + + /* --- Core PyObject call functions ------------------------------- */ /* Call a callable Python object without any arguments */ |