Skip to content

Commit e217840

Browse files
author
Anselm Kruis
committed
Issue python#135: fix memory leaks of types with Stackless extensions.
Fix several problems related with slp_prepare_slots(): - set Py_TPFLAGS_HAVE_STACKLESS_EXTENSION in slp_prepare_slots(). - for heap types free the allocated buffer in tp_dealloc - Allocate the memory from the object domain, because the blocks are small (about 74 bytes).
1 parent 709c150 commit e217840

File tree

2 files changed

+39
-7
lines changed

2 files changed

+39
-7
lines changed

Objects/typeobject.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3085,6 +3085,23 @@ type_dealloc(PyTypeObject *type)
30853085
Py_XDECREF(et->ht_slots);
30863086
if (et->ht_cached_keys)
30873087
_PyDictKeys_DecRef(et->ht_cached_keys);
3088+
3089+
#ifdef STACKLESS
3090+
/* A type's tp_as_mapping is heap allocated, if
3091+
* the flag Py_TPFLAGS_HAVE_STACKLESS_EXTENSION is set.
3092+
* The allocation happens in stacklessmodule.c
3093+
* function slp_prepare_slots().
3094+
*/
3095+
if (type->tp_as_mapping &&
3096+
(type->tp_flags & Py_TPFLAGS_HAVE_STACKLESS_EXTENSION)) {
3097+
void *tp_as_mapping = type->tp_as_mapping;
3098+
assert(type->tp_flags & Py_TPFLAGS_HEAPTYPE);
3099+
type->tp_flags &= ~Py_TPFLAGS_HAVE_STACKLESS_EXTENSION;
3100+
type->tp_as_mapping = NULL;
3101+
PyObject_Free(tp_as_mapping);
3102+
}
3103+
#endif
3104+
30883105
Py_TYPE(type)->tp_free((PyObject *)type);
30893106
}
30903107

Stackless/module/stacklessmodule.c

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1649,29 +1649,45 @@ Please refer to their documentation.\n\
16491649

16501650
/* This function is called to make sure the type has
16511651
* space in its tp_as_mapping to hold the slpslots. If it has
1652-
* the Py_TMPFLAGS_HAVE_STACKLESS_EXTENSION bit, then any struct present
1652+
* the Py_TPFLAGS_HAVE_STACKLESS_EXTENSION bit, then any struct present
16531653
* is deemed large enough. But if it is missing, then a struct already
16541654
* present needs to be grown.
1655+
*
1656+
* This function is the only place where we set Py_TPFLAGS_HAVE_STACKLESS_EXTENSION
1657+
* for heap types (== type with Py_TPFLAGS_HEAPTYPE). This way we can free
1658+
* the memory later in type_dealloc() in typeobject.c.
16551659
*/
16561660
int
16571661
slp_prepare_slots(PyTypeObject * type)
16581662
{
16591663
PyMappingMethods *map, *old = type->tp_as_mapping;
16601664
if (old == NULL || !(type->tp_flags & Py_TPFLAGS_HAVE_STACKLESS_EXTENSION)) {
16611665
/* need to allocate a new struct */
1662-
map = (PyMappingMethods *)PyMem_MALLOC(sizeof(PyMappingMethods));
1666+
1667+
/* For heap types ensure, that 'old' is part of the
1668+
* PyHeapTypeObject. Otherwise we would leak 'old'.
1669+
*/
1670+
assert(!(type->tp_flags & Py_TPFLAGS_HEAPTYPE) ||
1671+
(old == (PyMappingMethods*)
1672+
&((PyHeapTypeObject*)type)->as_mapping));
1673+
1674+
map = (PyMappingMethods *)PyObject_Calloc(1, sizeof(PyMappingMethods));
16631675
if (map == NULL) {
16641676
PyErr_NoMemory();
16651677
return -1;
1666-
}
1667-
memset(map, 0, sizeof(PyMappingMethods));
1678+
}
16681679
if (old) {
16691680
/* copy the old method slots, and mark the type */
16701681
memcpy(map, old, offsetof(PyMappingMethods, slpflags));
1671-
type->tp_flags |= Py_TPFLAGS_HAVE_STACKLESS_EXTENSION;
16721682
}
1673-
/* we are leaking this pointer */
1683+
/* We are leaking 'map' and 'old', except for heap types
1684+
* (with Py_TPFLAGS_HEAPTYPE set)). Theses types have a
1685+
* tp_dealloc function, which frees 'map'.
1686+
* For heap types 'old' is a member of PyHeapTypeObject and
1687+
* must not be freed.
1688+
*/
16741689
type->tp_as_mapping = map;
1690+
type->tp_flags |= Py_TPFLAGS_HAVE_STACKLESS_EXTENSION;
16751691
}
16761692
return 0;
16771693
}
@@ -1692,7 +1708,6 @@ static int init_stackless_methods(void)
16921708
if (ind)
16931709
t = *((PyTypeObject **)t);
16941710
/* this type has stackless slot methods. Set the flag */
1695-
t->tp_flags |= Py_TPFLAGS_HAVE_STACKLESS_EXTENSION;
16961711
if (slp_prepare_slots(t))
16971712
return -1;
16981713
((signed char *) t->tp_as_mapping)[ofs] = -1;

0 commit comments

Comments
 (0)