Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 3cfe754

Browse files
committed
PyType_Ready(): Complain if the type is a base type, and gc'able, and
tp_free is NULL or PyObject_Del at the end. Because it's a base type it must call tp_free in its dealloc function, and because it's gc'able it must not call PyObject_Del. inherit_slots(): Don't inherit tp_free unless the type and its base agree about whether they're gc'able. If the type is gc'able and the base is not, and the base uses the default PyObject_Del for its tp_free, give the type PyObject_GC_Del for its tp_free (the appropriate default for a gc'able type). cPickle.c: The Pickler and Unpickler types claim to be base classes and gc'able, but their dealloc functions didn't call tp_free. Repaired that. Also call PyType_Ready() on these typeobjects, so that the correct (PyObject_GC_Del) default memory-freeing function gets plugged into these types' tp_free slots.
1 parent 4d508ad commit 3cfe754

3 files changed

Lines changed: 49 additions & 3 deletions

File tree

Misc/NEWS

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,17 @@ Build
7575
C API
7676
-----
7777

78+
- PyType_Ready(): If a type declares that it participates in gc
79+
(Py_TPFLAGS_HAVE_GC), and its base class does not, and its base class's
80+
tp_free slot is the default _PyObject_Del, and type does not define
81+
a tp_free slot itself, _PyObject_GC_Del is assigned to type->tp_free.
82+
Previously _PyObject_Del was inherited, which could at best lead to a
83+
segfault. In addition, if even after this magic the type's tp_free
84+
slot is _PyObject_Del or NULL, and the type is a base type
85+
(Py_TPFLAGS_BASETYPE), TypeError is raised: since the type is a base
86+
type, its dealloc function must call type->tp_free, and since the type
87+
is gc'able, tp_free must not be NULL or _PyObject_Del.
88+
7889
New platforms
7990
-------------
8091

Modules/cPickle.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2853,7 +2853,7 @@ Pickler_dealloc(Picklerobject *self)
28532853
Py_XDECREF(self->inst_pers_func);
28542854
Py_XDECREF(self->dispatch_table);
28552855
PyMem_Free(self->write_buf);
2856-
PyObject_GC_Del(self);
2856+
self->ob_type->tp_free((PyObject *)self);
28572857
}
28582858

28592859
static int
@@ -5212,7 +5212,7 @@ Unpickler_dealloc(Unpicklerobject *self)
52125212
free(self->buf);
52135213
}
52145214

5215-
PyObject_GC_Del(self);
5215+
self->ob_type->tp_free((PyObject *)self);
52165216
}
52175217

52185218
static int
@@ -5534,6 +5534,11 @@ init_stuff(PyObject *module_dict)
55345534

55355535
#define INIT_STR(S) if (!( S ## _str=PyString_InternFromString(#S))) return -1;
55365536

5537+
if (PyType_Ready(&Unpicklertype) < 0)
5538+
return -1;
5539+
if (PyType_Ready(&Picklertype) < 0)
5540+
return -1;
5541+
55375542
INIT_STR(__class__);
55385543
INIT_STR(__getinitargs__);
55395544
INIT_STR(__dict__);

Objects/typeobject.c

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3044,8 +3044,25 @@ inherit_slots(PyTypeObject *type, PyTypeObject *base)
30443044
COPYSLOT(tp_dictoffset);
30453045
COPYSLOT(tp_init);
30463046
COPYSLOT(tp_alloc);
3047-
COPYSLOT(tp_free);
30483047
COPYSLOT(tp_is_gc);
3048+
if ((type->tp_flags & Py_TPFLAGS_HAVE_GC) ==
3049+
(base->tp_flags & Py_TPFLAGS_HAVE_GC)) {
3050+
/* They agree about gc. */
3051+
COPYSLOT(tp_free);
3052+
}
3053+
else if ((type->tp_flags & Py_TPFLAGS_HAVE_GC) &&
3054+
type->tp_free == NULL &&
3055+
base->tp_free == _PyObject_Del) {
3056+
/* A bit of magic to plug in the correct default
3057+
* tp_free function when a derived class adds gc,
3058+
* didn't define tp_free, and the base uses the
3059+
* default non-gc tp_free.
3060+
*/
3061+
type->tp_free = PyObject_GC_Del;
3062+
}
3063+
/* else they didn't agree about gc, and there isn't something
3064+
* obvious to be done -- the type is on its own.
3065+
*/
30493066
}
30503067
}
30513068

@@ -3149,6 +3166,19 @@ PyType_Ready(PyTypeObject *type)
31493166
inherit_slots(type, (PyTypeObject *)b);
31503167
}
31513168

3169+
/* Sanity check for tp_free. */
3170+
if (PyType_IS_GC(type) && (type->tp_flags & Py_TPFLAGS_BASETYPE) &&
3171+
(type->tp_free == NULL || type->tp_free == PyObject_Del)) {
3172+
/* This base class needs to call tp_free, but doesn't have
3173+
* one, or its tp_free is for non-gc'ed objects.
3174+
*/
3175+
PyErr_Format(PyExc_TypeError, "type '%.100s' participates in "
3176+
"gc and is a base type but has inappropriate "
3177+
"tp_free slot",
3178+
type->tp_name);
3179+
goto error;
3180+
}
3181+
31523182
/* if the type dictionary doesn't contain a __doc__, set it from
31533183
the tp_doc slot.
31543184
*/

0 commit comments

Comments
 (0)