diff options
author | Victor Stinner <vstinner@python.org> | 2020-02-05 12:12:19 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-02-05 12:12:19 (GMT) |
commit | f58bd7c1693fe041f7296a5778d0a11287895648 (patch) | |
tree | 066423d4c91278ace5f1f9159436fc2917ed2af8 | |
parent | 0fa4f43db086ac3459811cca4ec5201ffbee694a (diff) | |
download | cpython-f58bd7c1693fe041f7296a5778d0a11287895648.zip cpython-f58bd7c1693fe041f7296a5778d0a11287895648.tar.gz cpython-f58bd7c1693fe041f7296a5778d0a11287895648.tar.bz2 |
bpo-39542: Make PyObject_INIT() opaque in limited C API (GH-18363)
In the limited C API, PyObject_INIT() and PyObject_INIT_VAR() are now
defined as aliases to PyObject_Init() and PyObject_InitVar() to make
their implementation opaque. It avoids to leak implementation details
in the limited C API.
Exclude the following functions from the limited C API, move them
from object.h to cpython/object.h:
* _Py_NewReference()
* _Py_ForgetReference()
* _PyTraceMalloc_NewReference()
* _Py_GetRefTotal()
-rw-r--r-- | Include/cpython/object.h | 16 | ||||
-rw-r--r-- | Include/cpython/objimpl.h | 33 | ||||
-rw-r--r-- | Include/object.h | 15 | ||||
-rw-r--r-- | Include/objimpl.h | 43 | ||||
-rw-r--r-- | Misc/NEWS.d/next/C API/2020-02-05-12-40-51.bpo-39542.si-_Zq.rst | 7 | ||||
-rw-r--r-- | Objects/object.c | 12 |
6 files changed, 77 insertions, 49 deletions
diff --git a/Include/cpython/object.h b/Include/cpython/object.h index 3c4bf5b..e36f824 100644 --- a/Include/cpython/object.h +++ b/Include/cpython/object.h @@ -6,6 +6,22 @@ extern "C" { #endif +PyAPI_FUNC(void) _Py_NewReference(PyObject *op); + +#ifdef Py_TRACE_REFS +/* Py_TRACE_REFS is such major surgery that we call external routines. */ +PyAPI_FUNC(void) _Py_ForgetReference(PyObject *); +#endif + +/* Update the Python traceback of an object. This function must be called + when a memory block is reused from a free list. */ +PyAPI_FUNC(int) _PyTraceMalloc_NewReference(PyObject *op); + +#ifdef Py_REF_DEBUG +PyAPI_FUNC(Py_ssize_t) _Py_GetRefTotal(void); +#endif + + /********************* String Literals ****************************************/ /* This structure helps managing static strings. The basic usage goes like this: Instead of doing diff --git a/Include/cpython/objimpl.h b/Include/cpython/objimpl.h index f121922..3f14814 100644 --- a/Include/cpython/objimpl.h +++ b/Include/cpython/objimpl.h @@ -6,6 +6,39 @@ extern "C" { #endif +/* Inline functions trading binary compatibility for speed: + PyObject_INIT() is the fast version of PyObject_Init(), and + PyObject_INIT_VAR() is the fast version of PyObject_InitVar(). + + These inline functions must not be called with op=NULL. */ +static inline PyObject* +_PyObject_INIT(PyObject *op, PyTypeObject *typeobj) +{ + assert(op != NULL); + Py_TYPE(op) = typeobj; + if (PyType_GetFlags(typeobj) & Py_TPFLAGS_HEAPTYPE) { + Py_INCREF(typeobj); + } + _Py_NewReference(op); + return op; +} + +#define PyObject_INIT(op, typeobj) \ + _PyObject_INIT(_PyObject_CAST(op), (typeobj)) + +static inline PyVarObject* +_PyObject_INIT_VAR(PyVarObject *op, PyTypeObject *typeobj, Py_ssize_t size) +{ + assert(op != NULL); + Py_SIZE(op) = size; + PyObject_INIT((PyObject *)op, typeobj); + return op; +} + +#define PyObject_INIT_VAR(op, typeobj, size) \ + _PyObject_INIT_VAR(_PyVarObject_CAST(op), (typeobj), (size)) + + /* This function returns the number of allocated memory blocks, regardless of size */ PyAPI_FUNC(Py_ssize_t) _Py_GetAllocatedBlocks(void); diff --git a/Include/object.h b/Include/object.h index 4506757..91855d0 100644 --- a/Include/object.h +++ b/Include/object.h @@ -233,8 +233,7 @@ PyAPI_FUNC(int) PyObject_SetAttr(PyObject *, PyObject *, PyObject *); PyAPI_FUNC(int) PyObject_HasAttr(PyObject *, PyObject *); PyAPI_FUNC(PyObject *) PyObject_SelfIter(PyObject *); PyAPI_FUNC(PyObject *) PyObject_GenericGetAttr(PyObject *, PyObject *); -PyAPI_FUNC(int) PyObject_GenericSetAttr(PyObject *, - PyObject *, PyObject *); +PyAPI_FUNC(int) PyObject_GenericSetAttr(PyObject *, PyObject *, PyObject *); #if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03030000 PyAPI_FUNC(int) PyObject_GenericSetDict(PyObject *, PyObject *, void *); #endif @@ -381,20 +380,8 @@ you can count such references to the type object.) PyAPI_DATA(Py_ssize_t) _Py_RefTotal; PyAPI_FUNC(void) _Py_NegativeRefcount(const char *filename, int lineno, PyObject *op); -PyAPI_FUNC(Py_ssize_t) _Py_GetRefTotal(void); #endif /* Py_REF_DEBUG */ -/* Update the Python traceback of an object. This function must be called - when a memory block is reused from a free list. */ -PyAPI_FUNC(int) _PyTraceMalloc_NewReference(PyObject *op); - -PyAPI_FUNC(void) _Py_NewReference(PyObject *op); - -#ifdef Py_TRACE_REFS -/* Py_TRACE_REFS is such major surgery that we call external routines. */ -PyAPI_FUNC(void) _Py_ForgetReference(PyObject *); -#endif - PyAPI_FUNC(void) _Py_Dealloc(PyObject *); static inline void _Py_INCREF(PyObject *op) diff --git a/Include/objimpl.h b/Include/objimpl.h index 2337d8a..4591925 100644 --- a/Include/objimpl.h +++ b/Include/objimpl.h @@ -127,40 +127,21 @@ PyAPI_FUNC(PyVarObject *) _PyObject_NewVar(PyTypeObject *, Py_ssize_t); #define PyObject_NewVar(type, typeobj, n) \ ( (type *) _PyObject_NewVar((typeobj), (n)) ) -/* Inline functions trading binary compatibility for speed: - PyObject_INIT() is the fast version of PyObject_Init(), and - PyObject_INIT_VAR() is the fast version of PyObject_InitVar. - See also pymem.h. - - These inline functions expect non-NULL object pointers. */ -static inline PyObject* -_PyObject_INIT(PyObject *op, PyTypeObject *typeobj) -{ - assert(op != NULL); - Py_TYPE(op) = typeobj; - if (PyType_GetFlags(typeobj) & Py_TPFLAGS_HEAPTYPE) { - Py_INCREF(typeobj); - } - _Py_NewReference(op); - return op; -} - -#define PyObject_INIT(op, typeobj) \ - _PyObject_INIT(_PyObject_CAST(op), (typeobj)) +#define _PyObject_SIZE(typeobj) ( (typeobj)->tp_basicsize ) -static inline PyVarObject* -_PyObject_INIT_VAR(PyVarObject *op, PyTypeObject *typeobj, Py_ssize_t size) -{ - assert(op != NULL); - Py_SIZE(op) = size; - PyObject_INIT((PyObject *)op, typeobj); - return op; -} -#define PyObject_INIT_VAR(op, typeobj, size) \ - _PyObject_INIT_VAR(_PyVarObject_CAST(op), (typeobj), (size)) +#ifdef Py_LIMITED_API +/* Define PyObject_INIT() and PyObject_INIT_VAR() as aliases to PyObject_Init() + and PyObject_InitVar() in the limited C API for compatibility with the + CPython C API. */ +# define PyObject_INIT(op, typeobj) \ + PyObject_Init(_PyObject_CAST(op), (typeobj)) +# define PyObject_INIT_VAR(op, typeobj, size) \ + PyObject_InitVar(_PyVarObject_CAST(op), (typeobj), (size)) +#else +/* PyObject_INIT() and PyObject_INIT_VAR() are defined in cpython/objimpl.h */ +#endif -#define _PyObject_SIZE(typeobj) ( (typeobj)->tp_basicsize ) /* _PyObject_VAR_SIZE returns the number of bytes (as size_t) allocated for a vrbl-size object with nitems items, exclusive of gc overhead (if any). The diff --git a/Misc/NEWS.d/next/C API/2020-02-05-12-40-51.bpo-39542.si-_Zq.rst b/Misc/NEWS.d/next/C API/2020-02-05-12-40-51.bpo-39542.si-_Zq.rst new file mode 100644 index 0000000..7473577 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2020-02-05-12-40-51.bpo-39542.si-_Zq.rst @@ -0,0 +1,7 @@ +In the limited C API, ``PyObject_INIT()`` and ``PyObject_INIT_VAR()`` are +now defined as aliases to :c:func:`PyObject_Init` and +:c:func:`PyObject_InitVar` to make their implementation opaque. It avoids to +leak implementation details in the limited C API. Exclude the following +functions from the limited C API: ``_Py_NewReference()``, +``_Py_ForgetReference()``, ``_PyTraceMalloc_NewReference()`` and +``_Py_GetRefTotal()``. diff --git a/Objects/object.c b/Objects/object.c index 1884819..43b838a 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -139,9 +139,11 @@ Py_DecRef(PyObject *o) PyObject * PyObject_Init(PyObject *op, PyTypeObject *tp) { - if (op == NULL) + /* Any changes should be reflected in PyObject_INIT() macro */ + if (op == NULL) { return PyErr_NoMemory(); - /* Any changes should be reflected in PyObject_INIT (objimpl.h) */ + } + Py_TYPE(op) = tp; if (PyType_GetFlags(tp) & Py_TPFLAGS_HEAPTYPE) { Py_INCREF(tp); @@ -153,9 +155,11 @@ PyObject_Init(PyObject *op, PyTypeObject *tp) PyVarObject * PyObject_InitVar(PyVarObject *op, PyTypeObject *tp, Py_ssize_t size) { - if (op == NULL) + /* Any changes should be reflected in PyObject_INIT_VAR() macro */ + if (op == NULL) { return (PyVarObject *) PyErr_NoMemory(); - /* Any changes should be reflected in PyObject_INIT_VAR */ + } + Py_SIZE(op) = size; PyObject_Init((PyObject *)op, tp); return op; |