Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 364f0b0

Browse files
eduardo-elizondoencukou
authored andcommitted
bpo-35810: Incref heap-allocated types in PyObject_Init (GH-11661)
* Incref heap-allocated types in PyObject_Init * Add documentation and porting notes to What's New
1 parent 1fc5bf2 commit 364f0b0

File tree

8 files changed

+89
-10
lines changed

8 files changed

+89
-10
lines changed

Doc/whatsnew/3.8.rst

+67
Original file line numberDiff line numberDiff line change
@@ -509,6 +509,12 @@ Build and C API Changes
509509
``1`` for objects implementing ``__index__()``.
510510
(Contributed by Serhiy Storchaka in :issue:`36048`.)
511511

512+
* Heap-allocated type objects will now increase their reference count
513+
in :c:func:`PyObject_Init` (and its parallel macro ``PyObject_INIT``)
514+
instead of in :c:func:`PyType_GenericAlloc`. Types that modify instance
515+
allocation or deallocation may need to be adjusted.
516+
(Contributed by Eddie Elizondo in :issue:`35810`.)
517+
512518

513519
Deprecated
514520
==========
@@ -732,6 +738,67 @@ Changes in the C API
732738
(Contributed by Inada Naoki in :issue:`36381`.)
733739

734740

741+
Changes in the C API
742+
--------------------------
743+
744+
* Instances of heap-allocated types (such as those created with
745+
:c:func:`PyType_FromSpec`) hold a reference to their type object.
746+
Increasing the reference count of these type objects has been moved from
747+
:c:func:`PyType_GenericAlloc` to the more low-level functions,
748+
:c:func:`PyObject_Init` and :c:func:`PyObject_INIT`.
749+
This makes types created through :c:func:`PyType_FromSpec` behave like
750+
other classes in managed code.
751+
752+
Statically allocated types are not affected.
753+
754+
For the vast majority of cases, there should be no side effect.
755+
However, types that manually increase the reference count after allocating
756+
an instance (perhaps to work around the bug) may now become immortal.
757+
To avoid this, these classes need to call Py_DECREF on the type object
758+
during instance deallocation.
759+
760+
To correctly port these types into 3.8, please apply the following
761+
changes:
762+
763+
* Remove :c:macro:`Py_INCREF` on the type object after allocating an
764+
instance - if any.
765+
This may happen after calling :c:func:`PyObject_New`,
766+
:c:func:`PyObject_NewVar`, :c:func:`PyObject_GC_New`,
767+
:c:func:`PyObject_GC_NewVar`, or any other custom allocator that uses
768+
:c:func:`PyObject_Init` or :c:func:`PyObject_INIT`.
769+
770+
Example::
771+
772+
static foo_struct *
773+
foo_new(PyObject *type) {
774+
foo_struct *foo = PyObject_GC_New(foo_struct, (PyTypeObject *) type);
775+
if (foo == NULL)
776+
return NULL;
777+
#if PY_VERSION_HEX < 0x03080000
778+
// Workaround for Python issue 35810; no longer necessary in Python 3.8
779+
PY_INCREF(type)
780+
#endif
781+
return foo;
782+
}
783+
784+
* Ensure that all custom ``tp_dealloc`` functions of heap-allocated types
785+
decrease the type's reference count.
786+
787+
Example::
788+
789+
static void
790+
foo_dealloc(foo_struct *instance) {
791+
PyObject *type = Py_TYPE(instance);
792+
PyObject_GC_Del(instance);
793+
#if PY_VERSION_HEX >= 0x03080000
794+
// This was not needed before Python 3.8 (Python issue 35810)
795+
Py_DECREF(type);
796+
#endif
797+
}
798+
799+
(Contributed by Eddie Elizondo in :issue:`35810`.)
800+
801+
735802
CPython bytecode changes
736803
------------------------
737804

Include/objimpl.h

+3
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,9 @@ _PyObject_INIT(PyObject *op, PyTypeObject *typeobj)
138138
{
139139
assert(op != NULL);
140140
Py_TYPE(op) = typeobj;
141+
if (PyType_GetFlags(typeobj) & Py_TPFLAGS_HEAPTYPE) {
142+
Py_INCREF(typeobj);
143+
}
141144
_Py_NewReference(op);
142145
return op;
143146
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Modify ``PyObject_Init`` to correctly increase the refcount of heap-
2+
allocated Type objects. Also fix the refcounts of the heap-allocated types
3+
that were either doing this manually or not decreasing the type's refcount
4+
in tp_dealloc

Modules/_curses_panel.c

+5-1
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,10 @@ PyCursesPanel_New(PANEL *pan, PyCursesWindowObject *wo)
250250
static void
251251
PyCursesPanel_Dealloc(PyCursesPanelObject *po)
252252
{
253-
PyObject *obj = (PyObject *) panel_userptr(po->pan);
253+
PyObject *tp, *obj;
254+
255+
tp = (PyObject *) Py_TYPE(po);
256+
obj = (PyObject *) panel_userptr(po->pan);
254257
if (obj) {
255258
(void)set_panel_userptr(po->pan, NULL);
256259
Py_DECREF(obj);
@@ -261,6 +264,7 @@ PyCursesPanel_Dealloc(PyCursesPanelObject *po)
261264
remove_lop(po);
262265
}
263266
PyObject_DEL(po);
267+
Py_DECREF(tp);
264268
}
265269

266270
/* panel_above(NULL) returns the bottom panel in the stack. To get

Modules/_tkinter.c

-3
Original file line numberDiff line numberDiff line change
@@ -617,7 +617,6 @@ Tkapp_New(const char *screenName, const char *className,
617617
v = PyObject_New(TkappObject, (PyTypeObject *) Tkapp_Type);
618618
if (v == NULL)
619619
return NULL;
620-
Py_INCREF(Tkapp_Type);
621620

622621
v->interp = Tcl_CreateInterp();
623622
v->wantobjects = wantobjects;
@@ -802,7 +801,6 @@ newPyTclObject(Tcl_Obj *arg)
802801
self = PyObject_New(PyTclObject, (PyTypeObject *) PyTclObject_Type);
803802
if (self == NULL)
804803
return NULL;
805-
Py_INCREF(PyTclObject_Type);
806804
Tcl_IncrRefCount(arg);
807805
self->value = arg;
808806
self->string = NULL;
@@ -2722,7 +2720,6 @@ Tktt_New(PyObject *func)
27222720
v = PyObject_New(TkttObject, (PyTypeObject *) Tktt_Type);
27232721
if (v == NULL)
27242722
return NULL;
2725-
Py_INCREF(Tktt_Type);
27262723

27272724
Py_INCREF(func);
27282725
v->token = NULL;

Objects/object.c

+5-3
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,9 @@ PyObject_Init(PyObject *op, PyTypeObject *tp)
230230
return PyErr_NoMemory();
231231
/* Any changes should be reflected in PyObject_INIT (objimpl.h) */
232232
Py_TYPE(op) = tp;
233+
if (PyType_GetFlags(tp) & Py_TPFLAGS_HEAPTYPE) {
234+
Py_INCREF(tp);
235+
}
233236
_Py_NewReference(op);
234237
return op;
235238
}
@@ -240,9 +243,8 @@ PyObject_InitVar(PyVarObject *op, PyTypeObject *tp, Py_ssize_t size)
240243
if (op == NULL)
241244
return (PyVarObject *) PyErr_NoMemory();
242245
/* Any changes should be reflected in PyObject_INIT_VAR */
243-
op->ob_size = size;
244-
Py_TYPE(op) = tp;
245-
_Py_NewReference((PyObject *)op);
246+
Py_SIZE(op) = size;
247+
PyObject_Init((PyObject *)op, tp);
246248
return op;
247249
}
248250

Objects/structseq.c

+5
Original file line numberDiff line numberDiff line change
@@ -63,12 +63,17 @@ static void
6363
structseq_dealloc(PyStructSequence *obj)
6464
{
6565
Py_ssize_t i, size;
66+
PyTypeObject *tp;
6667

68+
tp = (PyTypeObject *) Py_TYPE(obj);
6769
size = REAL_SIZE(obj);
6870
for (i = 0; i < size; ++i) {
6971
Py_XDECREF(obj->ob_item[i]);
7072
}
7173
PyObject_GC_Del(obj);
74+
if (PyType_GetFlags(tp) & Py_TPFLAGS_HEAPTYPE) {
75+
Py_DECREF(tp);
76+
}
7277
}
7378

7479
/*[clinic input]

Objects/typeobject.c

-3
Original file line numberDiff line numberDiff line change
@@ -987,9 +987,6 @@ PyType_GenericAlloc(PyTypeObject *type, Py_ssize_t nitems)
987987

988988
memset(obj, '\0', size);
989989

990-
if (type->tp_flags & Py_TPFLAGS_HEAPTYPE)
991-
Py_INCREF(type);
992-
993990
if (type->tp_itemsize == 0)
994991
(void)PyObject_INIT(obj, type);
995992
else

0 commit comments

Comments
 (0)