From 5061adeb1d67760a1c87e274390fcc1be64447a3 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 9 Dec 2020 02:00:52 +0100 Subject: [PATCH] Use Py_SET_SIZE() function Replace "Py_TYPE(obj)=type;" with "Py_SET_SIZE(obj, type);". The Py_SET_SIZE() was added to Python 3.9: copy pythoncapi_compat.h header to src/object/. The file comes from the project: https://github.com/pythoncapi/pythoncapi_compat On Python 3.10, Py_SET_SIZE() should now be used rather than using Py_TYPE() as an l-value: https://docs.python.org/dev/c-api/structures.html#c.Py_TYPE Context: https://bugs.python.org/issue39573 --- src/object/class.cpp | 8 +- src/object/enum.cpp | 4 +- src/object/function.cpp | 4 +- src/object/life_support.cpp | 4 +- src/object/pythoncapi_compat.h | 280 +++++++++++++++++++++++++++++++++ 5 files changed, 294 insertions(+), 6 deletions(-) create mode 100644 src/object/pythoncapi_compat.h diff --git a/src/object/class.cpp b/src/object/class.cpp index 9bb9683a31..b69e5d1e55 100644 --- a/src/object/class.cpp +++ b/src/object/class.cpp @@ -1,3 +1,5 @@ +#include "pythoncapi_compat.h" + // Copyright David Abrahams 2001. // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -208,7 +210,7 @@ namespace objects { if (static_data_object.tp_dict == 0) { - Py_TYPE(&static_data_object) = &PyType_Type; + Py_SET_TYPE(&static_data_object, &PyType_Type); static_data_object.tp_base = &PyProperty_Type; if (PyType_Ready(&static_data_object)) return 0; @@ -316,7 +318,7 @@ namespace objects { if (class_metatype_object.tp_dict == 0) { - Py_TYPE(&class_metatype_object) = &PyType_Type; + Py_SET_TYPE(&class_metatype_object, &PyType_Type); class_metatype_object.tp_base = &PyType_Type; if (PyType_Ready(&class_metatype_object)) return type_handle(); @@ -470,7 +472,7 @@ namespace objects { if (class_type_object.tp_dict == 0) { - Py_TYPE(&class_type_object) = incref(class_metatype().get()); + Py_SET_TYPE(&class_type_object, incref(class_metatype().get())); class_type_object.tp_base = &PyBaseObject_Type; if (PyType_Ready(&class_type_object)) return type_handle(); diff --git a/src/object/enum.cpp b/src/object/enum.cpp index 10122ad1da..14bfbaaaa0 100644 --- a/src/object/enum.cpp +++ b/src/object/enum.cpp @@ -1,3 +1,5 @@ +#include "pythoncapi_compat.h" + // Copyright David Abrahams 2002. // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -153,7 +155,7 @@ namespace { if (enum_type_object.tp_dict == 0) { - Py_TYPE(&enum_type_object) = incref(&PyType_Type); + Py_SET_TYPE(&enum_type_object, incref(&PyType_Type)); #if PY_VERSION_HEX >= 0x03000000 enum_type_object.tp_base = &PyLong_Type; #else diff --git a/src/object/function.cpp b/src/object/function.cpp index 9d4745d102..09d77cbaba 100644 --- a/src/object/function.cpp +++ b/src/object/function.cpp @@ -1,3 +1,5 @@ +#include "pythoncapi_compat.h" + // Copyright David Abrahams 2001. // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -107,7 +109,7 @@ function::function( PyObject* p = this; if (Py_TYPE(&function_type) == 0) { - Py_TYPE(&function_type) = &PyType_Type; + Py_SET_TYPE(&function_type, &PyType_Type); ::PyType_Ready(&function_type); } diff --git a/src/object/life_support.cpp b/src/object/life_support.cpp index b7e9aa861e..e4b4d9385c 100644 --- a/src/object/life_support.cpp +++ b/src/object/life_support.cpp @@ -1,3 +1,5 @@ +#include "pythoncapi_compat.h" + // Copyright David Abrahams 2002. // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -93,7 +95,7 @@ PyObject* make_nurse_and_patient(PyObject* nurse, PyObject* patient) if (Py_TYPE(&life_support_type) == 0) { - Py_TYPE(&life_support_type) = &PyType_Type; + Py_SET_TYPE(&life_support_type, &PyType_Type); PyType_Ready(&life_support_type); } diff --git a/src/object/pythoncapi_compat.h b/src/object/pythoncapi_compat.h new file mode 100644 index 0000000000..9d7b86629d --- /dev/null +++ b/src/object/pythoncapi_compat.h @@ -0,0 +1,280 @@ +// Header file providing new functions of the Python C API to old Python +// versions. +// +// File distributed under the MIT license. +// +// Homepage: +// https://github.com/pythoncapi/pythoncapi_compat +// +// Latest version: +// https://raw.githubusercontent.com/pythoncapi/pythoncapi_compat/master/pythoncapi_compat.h +// +// SPDX-License-Identifier: MIT + +#ifndef PYTHONCAPI_COMPAT +#define PYTHONCAPI_COMPAT + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "frameobject.h" // PyFrameObject, PyFrame_GetBack() + + +// Cast argument to PyObject* type. +#ifndef _PyObject_CAST +# define _PyObject_CAST(op) ((PyObject*)(op)) +#endif + + +// bpo-42262 added Py_NewRef() to Python 3.10.0a3 +#if PY_VERSION_HEX < 0x030a00A3 && !defined(Py_NewRef) +static inline PyObject* _Py_NewRef(PyObject *obj) +{ + Py_INCREF(obj); + return obj; +} +#define Py_NewRef(obj) _Py_NewRef(_PyObject_CAST(obj)) +#endif + + +// bpo-42262 added Py_XNewRef() to Python 3.10.0a3 +#if PY_VERSION_HEX < 0x030a00A3 && !defined(Py_XNewRef) +static inline PyObject* _Py_XNewRef(PyObject *obj) +{ + Py_XINCREF(obj); + return obj; +} +#define Py_XNewRef(obj) _Py_XNewRef(_PyObject_CAST(obj)) +#endif + + +// bpo-39573 added Py_SET_REFCNT() to Python 3.9.0a4 +#if PY_VERSION_HEX < 0x030900A4 && !defined(Py_SET_REFCNT) +static inline void _Py_SET_REFCNT(PyObject *ob, Py_ssize_t refcnt) +{ + ob->ob_refcnt = refcnt; +} +#define Py_SET_REFCNT(ob, refcnt) _Py_SET_REFCNT((PyObject*)(ob), refcnt) +#endif + + +// bpo-39573 added Py_SET_TYPE() to Python 3.9.0a4 +#if PY_VERSION_HEX < 0x030900A4 && !defined(Py_SET_TYPE) +static inline void +_Py_SET_TYPE(PyObject *ob, PyTypeObject *type) +{ + ob->ob_type = type; +} +#define Py_SET_TYPE(ob, type) _Py_SET_TYPE((PyObject*)(ob), type) +#endif + + +// bpo-39573 added Py_SET_SIZE() to Python 3.9.0a4 +#if PY_VERSION_HEX < 0x030900A4 && !defined(Py_SET_SIZE) +static inline void +_Py_SET_SIZE(PyVarObject *ob, Py_ssize_t size) +{ + ob->ob_size = size; +} +#define Py_SET_SIZE(ob, size) _Py_SET_SIZE((PyVarObject*)(ob), size) +#endif + + +// bpo-40421 added PyFrame_GetCode() to Python 3.9.0b1 +#if PY_VERSION_HEX < 0x030900B1 +static inline PyCodeObject* +PyFrame_GetCode(PyFrameObject *frame) +{ + PyCodeObject *code; + assert(frame != NULL); + code = frame->f_code; + assert(code != NULL); + Py_INCREF(code); + return code; +} +#endif + +static inline PyCodeObject* +_PyFrame_GetCodeBorrow(PyFrameObject *frame) +{ + PyCodeObject *code = PyFrame_GetCode(frame); + Py_DECREF(code); + return code; // borrowed reference +} + + +// bpo-40421 added PyFrame_GetCode() to Python 3.9.0b1 +#if PY_VERSION_HEX < 0x030900B1 +static inline PyFrameObject* +PyFrame_GetBack(PyFrameObject *frame) +{ + PyFrameObject *back; + assert(frame != NULL); + back = frame->f_back; + Py_XINCREF(back); + return back; +} +#endif + +static inline PyFrameObject* +_PyFrame_GetBackBorrow(PyFrameObject *frame) +{ + PyFrameObject *back = PyFrame_GetBack(frame); + Py_XDECREF(back); + return back; // borrowed reference +} + + +// bpo-39947 added PyThreadState_GetInterpreter() to Python 3.9.0a5 +#if PY_VERSION_HEX < 0x030900A5 +static inline PyInterpreterState * +PyThreadState_GetInterpreter(PyThreadState *tstate) +{ + assert(tstate != NULL); + return tstate->interp; +} +#endif + + +// bpo-40429 added PyThreadState_GetFrame() to Python 3.9.0b1 +#if PY_VERSION_HEX < 0x030900B1 +static inline PyFrameObject* +PyThreadState_GetFrame(PyThreadState *tstate) +{ + PyFrameObject *frame; + assert(tstate != NULL); + frame = tstate->frame; + Py_XINCREF(frame); + return frame; +} +#endif + +static inline PyFrameObject* +_PyThreadState_GetFrameBorrow(PyThreadState *tstate) +{ + PyFrameObject *frame = PyThreadState_GetFrame(tstate); + Py_XDECREF(frame); + return frame; // borrowed reference +} + + +// bpo-39947 added PyInterpreterState_Get() to Python 3.9.0a5 +#if PY_VERSION_HEX < 0x030900A5 +static inline PyInterpreterState * +PyInterpreterState_Get(void) +{ + PyThreadState *tstate; + PyInterpreterState *interp; + + tstate = PyThreadState_GET(); + if (tstate == NULL) { + Py_FatalError("GIL released (tstate is NULL)"); + } + interp = tstate->interp; + if (interp == NULL) { + Py_FatalError("no current interpreter"); + } + return interp; +} +#endif + + +// bpo-39947 added PyInterpreterState_Get() to Python 3.9.0a6 +#if 0x030700A1 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x030900A6 +static inline uint64_t +PyThreadState_GetID(PyThreadState *tstate) +{ + assert(tstate != NULL); + return tstate->id; +} +#endif + + +// bpo-37194 added PyObject_CallNoArgs() to Python 3.9.0a1 +#if PY_VERSION_HEX < 0x030900A1 +static inline PyObject* +PyObject_CallNoArgs(PyObject *func) +{ + return PyObject_CallFunctionObjArgs(func, NULL); +} +#endif + + +// bpo-39245 made PyObject_CallOneArg() public (previously called +// _PyObject_CallOneArg) in Python 3.9.0a4 +#if PY_VERSION_HEX < 0x030900A4 +static inline PyObject* +PyObject_CallOneArg(PyObject *func, PyObject *arg) +{ + return PyObject_CallFunctionObjArgs(func, arg, NULL); +} +#endif + + +// bpo-40024 added PyModule_AddType() to Python 3.9.0a5 +#if PY_VERSION_HEX < 0x030900A5 +static inline int +PyModule_AddType(PyObject *module, PyTypeObject *type) +{ + const char *name, *dot; + + if (PyType_Ready(type) < 0) { + return -1; + } + + // inline _PyType_Name() + name = type->tp_name; + assert(name != NULL); + dot = strrchr(name, '.'); + if (dot != NULL) { + name = dot + 1; + } + + Py_INCREF(type); + if (PyModule_AddObject(module, name, (PyObject *)type) < 0) { + Py_DECREF(type); + return -1; + } + + return 0; +} +#endif + + +// bpo-40241 added PyObject_GC_IsTracked() to Python 3.9.0a6. +// bpo-4688 added _PyObject_GC_IS_TRACKED() to Python 2.7.0a2. +#if PY_VERSION_HEX < 0x030900A6 +static inline int +PyObject_GC_IsTracked(PyObject* obj) +{ + return (PyObject_IS_GC(obj) && _PyObject_GC_IS_TRACKED(obj)); +} +#endif + +// bpo-40241 added PyObject_GC_IsFinalized() to Python 3.9.0a6. +// bpo-18112 added _PyGCHead_FINALIZED() to Python 3.4.0 final. +#if PY_VERSION_HEX < 0x030900A6 && PY_VERSION_HEX >= 0x030400F0 +static inline int +PyObject_GC_IsFinalized(PyObject *obj) +{ + return (PyObject_IS_GC(obj) && _PyGCHead_FINALIZED((PyGC_Head *)(obj)-1)); +} +#endif + + +// bpo-39573 added Py_IS_TYPE() to Python 3.9.0a4 +#if PY_VERSION_HEX < 0x030900A4 && !defined(Py_IS_TYPE) +static inline int +_Py_IS_TYPE(const PyObject *ob, const PyTypeObject *type) { + return ob->ob_type == type; +} +#define Py_IS_TYPE(ob, type) _Py_IS_TYPE((const PyObject*)(ob), type) +#endif + + +#ifdef __cplusplus +} +#endif +#endif // PYTHONCAPI_COMPAT