diff --git a/Include/tupleobject.h b/Include/tupleobject.h index 257e05aeae8f30c..25dd7fc53f0c8c8 100644 --- a/Include/tupleobject.h +++ b/Include/tupleobject.h @@ -55,8 +55,17 @@ PyAPI_FUNC(void) _PyTuple_MaybeUntrack(PyObject *); /* Macro, trading safety for speed */ #ifndef Py_LIMITED_API -#define PyTuple_GET_ITEM(op, i) (((PyTupleObject *)(op))->ob_item[i]) -#define PyTuple_GET_SIZE(op) (assert(PyTuple_Check(op)),Py_SIZE(op)) + +#ifdef Py_DEBUG +PyAPI_FUNC(PyObject*) _PyTuple_GET_ITEM_impl(const PyObject *op, Py_ssize_t i); +PyAPI_FUNC(Py_ssize_t) _PyTuple_GET_SIZE_impl(const PyObject *op); + +# define PyTuple_GET_ITEM(op, i) _PyTuple_GET_ITEM_impl((PyObject *)(op), i) +# define PyTuple_GET_SIZE(op) _PyTuple_GET_SIZE_impl((PyObject *)(op)) +#else +# define PyTuple_GET_ITEM(op, i) (((PyTupleObject *)(op))->ob_item[i]) +# define PyTuple_GET_SIZE(op) (assert(PyTuple_Check(op)),Py_SIZE(op)) +#endif #ifdef Py_BUILD_CORE # define _PyTuple_ITEMS(op) ((((PyTupleObject *)(op))->ob_item)) diff --git a/Misc/NEWS.d/next/C API/2018-11-09-17-00-12.bpo-35199.9LxO8j.rst b/Misc/NEWS.d/next/C API/2018-11-09-17-00-12.bpo-35199.9LxO8j.rst new file mode 100644 index 000000000000000..67d55a782e35da4 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2018-11-09-17-00-12.bpo-35199.9LxO8j.rst @@ -0,0 +1,4 @@ +When Python is compiled in debug mode (Py_DEBUG), PyTuple_GET_ITEM() macro +becomes a function which implements sanity checks using assertions. It +should help to detect misusage of the C API. "&PyTuple_GET_ITEM(op, i)" is +now invalid in debug mode. diff --git a/Objects/tupleobject.c b/Objects/tupleobject.c index c997bc6fa2d0cf0..9d44fb0b9ff9958 100644 --- a/Objects/tupleobject.c +++ b/Objects/tupleobject.c @@ -134,6 +134,16 @@ PyTuple_New(Py_ssize_t size) return (PyObject *) op; } +#ifdef Py_DEBUG +Py_ssize_t +_PyTuple_GET_SIZE_impl(const PyObject *op) +{ + _PyObject_ASSERT((PyObject *)op, PyTuple_Check(op)); + return Py_SIZE(op); + +} +#endif + Py_ssize_t PyTuple_Size(PyObject *op) { @@ -145,6 +155,16 @@ PyTuple_Size(PyObject *op) return Py_SIZE(op); } +#ifdef Py_DEBUG +PyObject* +_PyTuple_GET_ITEM_impl(const PyObject *op, Py_ssize_t i) +{ + _PyObject_ASSERT((PyObject *)op, PyTuple_Check(op)); + assert(0 <= i && i < Py_SIZE(op)); + return ((PyTupleObject *)op) -> ob_item[i]; +} +#endif + PyObject * PyTuple_GetItem(PyObject *op, Py_ssize_t i) {