8000 bpo-39542: Make PyObject_INIT() opaque in limited C API (GH-18363) · python/cpython@f58bd7c · GitHub
[go: up one dir, main page]

Skip to content

Commit f58bd7c

Browse files
authored
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()
1 parent 0fa4f43 commit f58bd7c

File tree

6 files changed

+77
-49
lines changed

6 files changed

+77
-49
lines changed

Include/cpython/object.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,22 @@
66
extern "C" {
77
#endif
88

9+
PyAPI_FUNC(void) _Py_NewReference(PyObject *op);
10+
11+
#ifdef Py_TRACE_REFS
12+
/* Py_TRACE_REFS is such major surgery that we call external routines. */
13+
PyAPI_FUNC(void) _Py_ForgetReference(PyObject *);
14+
#endif
15+
16+
/* Update the Python traceback of an object. This function must be called
17+
when a memory block is reused from a free list. */
18+
PyAPI_FUNC(int) _PyTraceMalloc_NewReference(PyObject *op);
19+
20+
#ifdef Py_REF_DEBUG
21+
PyAPI_FUNC(Py_ssize_t) _Py_GetRefTotal(void);
22+
#endif
23+
24+
925
/********************* String Literals ****************************************/
1026
/* This structure helps managing static strings. The basic usage goes like this:
1127
Instead of doing

Include/cpython/objimpl.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,39 @@
66
extern "C" {
77
#endif
88

9+
/* Inline functions trading binary compatibility for speed:
10+
PyObject_INIT() is the fast version of PyObject_Init(), and
11+
PyObject_INIT_VAR() is the fast version of PyObject_InitVar().
12+
13+
These inline functions must not be called with op=NULL. */
14+
static inline PyObject*
15+
_PyObject_INIT(PyObject *op, PyTypeObject *typeobj)
16+
{
17+
assert(op != NULL);
18+
Py_TYPE(op) = typeobj;
19+
if (PyType_GetFlags(typeobj) & Py_TPFLAGS_HEAPTYPE) {
20+
Py_INCREF(typeobj);
10000 21+
}
22+
_Py_NewReference(op);
23+
return op;
24+
}
25+
26+
#define PyObject_INIT(op, typeobj) \
27+
_PyObject_INIT(_PyObject_CAST(op), (typeobj))
28+
29+
static inline PyVarObject*
30+
_PyObject_INIT_VAR(PyVarObject *op, PyTypeObject *typeobj, Py_ssize_t size)
31+
{
32+
assert(op != NULL);
33+
Py_SIZE(op) = size;
34+
PyObject_INIT((PyObject *)op, typeobj);
35+
return op;
36+
}
37+
38+
#define PyObject_INIT_VAR(op, typeobj, size) \
39+
_PyObject_INIT_VAR(_PyVarObject_CAST(op), (typeobj), (size))
40+
41+
942
/* This function returns the number of allocated memory blocks, regardless of size */
1043
PyAPI_FUNC(Py_ssize_t) _Py_GetAllocatedBlocks(void);
1144

Include/object.h

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -233,8 +233,7 @@ PyAPI_FUNC(int) PyObject_SetAttr(PyObject *, PyObject *, PyObject *);
233233
PyAPI_FUNC(int) PyObject_HasAttr(PyObject *, PyObject *);
234234
PyAPI_FUNC(PyObject *) PyObject_SelfIter(PyObject *);
235235
PyAPI_FUNC(PyObject *) PyObject_GenericGetAttr(PyObject *, PyObject *);
236-
PyAPI_FUNC(int) PyObject_GenericSetAttr(PyObject *,
237-
PyObject *, PyObject *);
236+
PyAPI_FUNC(int) PyObject_GenericSetAttr(PyObject *, PyObject *, PyObject *);
238237
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03030000
239238
PyAPI_FUNC(int) PyObject_GenericSetDict(PyObject *, PyObject *, void *);
240239
#endif
@@ -381,20 +380,8 @@ you can count such references to the type object.)
381380
PyAPI_DATA(Py_ssize_t) _Py_RefTotal;
382381
PyAPI_FUNC(void) _Py_NegativeRefcount(const char *filename, int lineno,
383382
PyObject *op);
384-
PyAPI_FUNC(Py_ssize_t) _Py_GetRefTotal(void);
385383
#endif /* Py_REF_DEBUG */
386384

387-
/* Update the Python traceback of an object. This function must be called
388-
when a memory block is reused from a free list. */
389-
PyAPI_FUNC(int) _PyTraceMalloc_NewReference(PyObject *op);
390-
391-
PyAPI_FUNC(void) _Py_NewReference(PyObject *op);
392-
393-
#ifdef Py_TRACE_REFS
394-
/* Py_TRACE_REFS is such major surgery that we call external routines. */
395-
PyAPI_FUNC(void) _Py_ForgetReference(PyObject *);
396-
#endif
397-
398385
PyAPI_FUNC(void) _Py_Dealloc(PyObject *);
399386

400387
static inline void _Py_INCREF(PyObject *op)

Include/objimpl.h

Lines changed: 12 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -127,40 +127,21 @@ PyAPI_FUNC(PyVarObject *) _PyObject_NewVar(PyTypeObject *, Py_ssize_t);
127127
#define PyObject_NewVar(type, typeobj, n) \
128128
( (type *) _PyObject_NewVar((typeobj), (n)) )
129129

130-
/* Inline functions trading binary compatibility for speed:
131-
PyObject_INIT() is the fast version of PyObject_Init(), and
132-
PyObject_INIT_VAR() is the fast version of PyObject_InitVar.
133-
See also pymem.h.
134-
135-
These inline functions expect non-NULL object pointers. */
136-
static inline PyObject*
137-
_PyObject_INIT(PyObject *op, PyTypeObject *typeobj)
138-
{
139-
assert(op != NULL);
140-
Py_TYPE(op) = typeobj;
141-
if (PyType_GetFlags(typeobj) & Py_TPFLAGS_HEAPTYPE) {
142-
Py_INCREF(typeobj);
143-
}
144-
_Py_NewReference(op);
145-
return op;
146-
}
147-
148-
#define PyObject_INIT(op, typeobj) \
149-
_PyObject_INIT(_PyObject_CAST(op), (typeobj))
130+
#define _PyObject_SIZE(typeobj) ( (typeobj)->tp_basicsize )
150131

151-
static inline PyVarObject*
152-
_PyObject_INIT_VAR(PyVarObject *op, PyTypeObject *typeobj, Py_ssize_t size)
153-
{
154-
assert(op != NULL);
155-
Py_SIZE(op) = size;
156-
PyObject_INIT((PyObject *)op, typeobj);
157-
return op;
158-
}
159132

160-
#define PyObject_INIT_VAR(op, typeobj, size) \
161-
_PyObject_INIT_VAR(_PyVarObject_CAST(op), (typeobj), (size))
133+
#ifdef Py_LIMITED_API
134+
/* Define PyObject_INIT() and PyObject_INIT_VAR() as aliases to PyObject_Init()
135+
and PyObject_InitVar() in the limited C API for compatibility with the
136+
CPython C API. */
137+
# define PyObject_INIT(op, typeobj) \
138+
PyObject_Init(_PyObject_CAST(op), (typeobj))
139+
# define PyObject_INIT_VAR(op, typeobj, size) \
140+
PyObject_InitVar(_PyVarObject_CAST(op), (typeobj), (size))
141+
#else
142+
/* PyObject_INIT() and PyObject_INIT_VAR() are defined in cpython/objimpl.h */
143+
#endif
162144

163-
#define _PyObject_SIZE(typeobj) ( (typeobj)->tp_basicsize )
164145

165146
/* _PyObject_VAR_SIZE returns the number of bytes (as size_t) allocated for a
166147
vrbl-size object with nitems items, exclusive of gc overhead (if any). The
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
In the limited C API, ``PyObject_INIT()`` and ``PyObject_INIT_VAR()`` are
2+
now defined as aliases to :c:func:`PyObject_Init` and
3+
:c:func:`PyObject_InitVar` to make their implementation opaque. It avoids to
4+
leak implementation details in the limited C API. Exclude the following
5+
functions from the limited C API: ``_Py_NewReference()``,
6+
``_Py_ForgetReference()``, ``_PyTraceMalloc_NewReference()`` and
7+
``_Py_GetRefTotal()``.

Objects/object.c

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -139,9 +139,11 @@ Py_DecRef(PyObject *o)
139139
PyObject *
140140
PyObject_Init(PyObject *op, PyTypeObject *tp)
141141
{
142-
if (op == NULL)
142+
/* Any changes should be reflected in PyObject_INIT() macro */
143+
if (op == NULL) {
143144
return PyErr_NoMemory();
144-
/* Any changes should be reflected in PyObject_INIT (objimpl.h) */
145+
}
146+
145147
Py_TYPE(op) = tp;
146148
if (PyType_GetFlags(tp) & Py_TPFLAGS_HEAPTYPE) {
147149
Py_INCREF(tp);
@@ -153,9 +155,11 @@ PyObject_Init(PyObject *op, PyTypeObject *tp)
153155
PyVarObject *
154156
PyObject_InitVar(PyVarObject *op, PyTypeObject *tp, Py_ssize_t size)
155157
{
156-
if (op == NULL)
158+
/* Any changes should be reflected in PyObject_INIT_VAR() macro */
159+
if (op == NULL) {
157160
return (PyVarObject *) PyErr_NoMemory();
158-
/* Any changes should be reflected in PyObject_INIT_VAR */
161+
}
162+
159163
Py_SIZE(op) = size;
160164
PyObject_Init((PyObject *)op, tp);
161165
return op;

0 commit comments

Comments
 (0)
0