@@ -1649,29 +1649,45 @@ Please refer to their documentation.\n\
1649
1649
1650
1650
/* This function is called to make sure the type has
1651
1651
* 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
1653
1653
* is deemed large enough. But if it is missing, then a struct already
1654
1654
* 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.
1655
1659
*/
1656
1660
int
1657
1661
slp_prepare_slots (PyTypeObject * type )
1658
1662
{
1659
1663
PyMappingMethods * map , * old = type -> tp_as_mapping ;
1660
1664
if (old == NULL || !(type -> tp_flags & Py_TPFLAGS_HAVE_STACKLESS_EXTENSION )) {
1661
1665
/* 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 ));
1663
1675
if (map == NULL ) {
1664
1676
PyErr_NoMemory ();
1665
1677
return -1 ;
1666
- }
1667
- memset (map , 0 , sizeof (PyMappingMethods ));
1678
+ }
1668
1679
if (old ) {
1669
1680
/* copy the old method slots, and mark the type */
1670
1681
memcpy (map , old , offsetof(PyMappingMethods , slpflags ));
1671
- type -> tp_flags |= Py_TPFLAGS_HAVE_STACKLESS_EXTENSION ;
1672
1682
}
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
+ */
1674
1689
type -> tp_as_mapping = map ;
1690
+ type -> tp_flags |= Py_TPFLAGS_HAVE_STACKLESS_EXTENSION ;
1675
1691
}
1676
1692
return 0 ;
1677
1693
}
@@ -1692,7 +1708,6 @@ static int init_stackless_methods(void)
1692
1708
if (ind )
1693
1709
t = * ((PyTypeObject * * )t );
1694
1710
/* this type has stackless slot methods. Set the flag */
1695
- t -> tp_flags |= Py_TPFLAGS_HAVE_STACKLESS_EXTENSION ;
1696
1711
if (slp_prepare_slots (t ))
1697
1712
return -1 ;
1698
1713
((signed char * ) t -> tp_as_mapping )[ofs ] = -1 ;
0 commit comments