bpo-39573: Convert Py_TYPE() and Py_SIZE() back to macros (GH-23366)

This change partically reverts
commit ad3252bad9
and the commit fe2978b3b9.

Many third party C extension modules rely on the ability of using
Py_TYPE() to set an object type: "Py_TYPE(obj) = type;" or to set an
object type using: "Py_SIZE(obj) = size;".
This commit is contained in:
Victor Stinner 2020-11-18 18:48:06 +01:00 committed by GitHub
parent 2156d964a1
commit 0e2ac21dd4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 35 additions and 26 deletions

View File

@ -68,9 +68,7 @@ the definition of all other Python objects.
Return a :term:`borrowed reference`. Return a :term:`borrowed reference`.
.. versionchanged:: 3.10 The :c:func:`Py_SET_TYPE` function must be used to set an object type.
:c:func:`Py_TYPE()` is changed to the inline static function.
Use :c:func:`Py_SET_TYPE()` to set an object type.
.. c:function:: int Py_IS_TYPE(PyObject *o, PyTypeObject *type) .. c:function:: int Py_IS_TYPE(PyObject *o, PyTypeObject *type)
@ -108,9 +106,7 @@ the definition of all other Python objects.
Get the size of the Python object *o*. Get the size of the Python object *o*.
.. versionchanged:: 3.10 The :c:func:`Py_SET_SIZE` function must be used to set an object size.
:c:func:`Py_SIZE()` is changed to the inline static function.
Use :c:func:`Py_SET_SIZE()` to set an object size.
.. c:function:: void Py_SET_SIZE(PyVarObject *o, Py_ssize_t size) .. c:function:: void Py_SET_SIZE(PyVarObject *o, Py_ssize_t size)

View File

@ -489,17 +489,6 @@ Porting to Python 3.10
<arg-parsing>` and the :pep:`353`. <arg-parsing>` and the :pep:`353`.
(Contributed by Victor Stinner in :issue:`40943`.) (Contributed by Victor Stinner in :issue:`40943`.)
* Since :c:func:`Py_TYPE()` is changed to the inline static function,
``Py_TYPE(obj) = new_type`` must be replaced with ``Py_SET_TYPE(obj, new_type)``:
see :c:func:`Py_SET_TYPE()` (available since Python 3.9). For backward
compatibility, this macro can be used::
#if PY_VERSION_HEX < 0x030900A4
# define Py_SET_TYPE(obj, type) ((Py_TYPE(obj) = (type)), (void)0)
#endif
(Contributed by Dong-hee Na in :issue:`39573`.)
* Since :c:func:`Py_REFCNT()` is changed to the inline static function, * Since :c:func:`Py_REFCNT()` is changed to the inline static function,
``Py_REFCNT(obj) = new_refcnt`` must be replaced with ``Py_SET_REFCNT(obj, new_refcnt)``: ``Py_REFCNT(obj) = new_refcnt`` must be replaced with ``Py_SET_REFCNT(obj, new_refcnt)``:
see :c:func:`Py_SET_REFCNT()` (available since Python 3.9). For backward see :c:func:`Py_SET_REFCNT()` (available since Python 3.9). For backward

View File

@ -128,16 +128,11 @@ static inline Py_ssize_t _Py_REFCNT(const PyObject *ob) {
#define Py_REFCNT(ob) _Py_REFCNT(_PyObject_CAST_CONST(ob)) #define Py_REFCNT(ob) _Py_REFCNT(_PyObject_CAST_CONST(ob))
static inline Py_ssize_t _Py_SIZE(const PyVarObject *ob) { // bpo-39573: The Py_SET_TYPE() function must be used to set an object type.
return ob->ob_size; #define Py_TYPE(ob) (_PyObject_CAST(ob)->ob_type)
}
#define Py_SIZE(ob) _Py_SIZE(_PyVarObject_CAST_CONST(ob))
// bpo-39573: The Py_SET_SIZE() function must be used to set an object size.
static inline PyTypeObject* _Py_TYPE(const PyObject *ob) { #define Py_SIZE(ob) (_PyVarObject_CAST(ob)->ob_size)
return ob->ob_type;
}
#define Py_TYPE(ob) _Py_TYPE(_PyObject_CAST_CONST(ob))
static inline int _Py_IS_TYPE(const PyObject *ob, const PyTypeObject *type) { static inline int _Py_IS_TYPE(const PyObject *ob, const PyTypeObject *type) {

View File

@ -0,0 +1,4 @@
Convert :c:func:`Py_TYPE` and :c:func:`Py_SIZE` back to macros to allow
using them as an l-value. Many third party C extension modules rely on the
ability of using Py_TYPE() and Py_SIZE() to set an object type and size:
``Py_TYPE(obj) = type;`` and ``Py_SIZE(obj) = size;``.

View File

@ -5612,6 +5612,30 @@ pynumber_tobase(PyObject *module, PyObject *args)
static PyObject *test_buildvalue_issue38913(PyObject *, PyObject *); static PyObject *test_buildvalue_issue38913(PyObject *, PyObject *);
static PyObject*
test_set_type_size(PyObject* self, PyObject* ignored)
{
PyObject *obj = PyList_New(0);
if (obj == NULL) {
return NULL;
}
// Ensure that following tests don't modify the object,
// to ensure that Py_DECREF() will not crash.
assert(Py_TYPE(obj) == &PyList_Type);
assert(Py_SIZE(obj) == 0);
// bpo-39573: Check that Py_TYPE() and Py_SIZE() can be used
// as l-values to set an object type and size.
Py_TYPE(obj) = &PyList_Type;
Py_SIZE(obj) = 0;
Py_DECREF(obj);
Py_RETURN_NONE;
}
static PyMethodDef TestMethods[] = { static PyMethodDef TestMethods[] = {
{"raise_exception", raise_exception, METH_VARARGS}, {"raise_exception", raise_exception, METH_VARARGS},
{"raise_memoryerror", raise_memoryerror, METH_NOARGS}, {"raise_memoryerror", raise_memoryerror, METH_NOARGS},
@ -5883,6 +5907,7 @@ static PyMethodDef TestMethods[] = {
{"meth_fastcall_keywords", (PyCFunction)(void(*)(void))meth_fastcall_keywords, METH_FASTCALL|METH_KEYWORDS}, {"meth_fastcall_keywords", (PyCFunction)(void(*)(void))meth_fastcall_keywords, METH_FASTCALL|METH_KEYWORDS},
{"pynumber_tobase", pynumber_tobase, METH_VARARGS}, {"pynumber_tobase", pynumber_tobase, METH_VARARGS},
{"without_gc", without_gc, METH_O}, {"without_gc", without_gc, METH_O},
{"test_set_type_size", test_set_type_size, METH_NOARGS},
{NULL, NULL} /* sentinel */ {NULL, NULL} /* sentinel */
}; };