From cb3d4065febed88ba3f7129e8188dc0d4c9cba57 Mon Sep 17 00:00:00 2001 From: bennorth Date: Thu, 20 Jul 2017 14:21:31 +0100 Subject: [PATCH] Fix refcounting for tp_base objects of new types (#950) To fix a difficult-to-reproduce segfault on Python interpreter exit, ensure that the tp_base field of a handful of new heap-types is counted as a reference to that base type object. --- include/pybind11/class_support.h | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/include/pybind11/class_support.h b/include/pybind11/class_support.h index 2bfc5a8d..9516bd64 100644 --- a/include/pybind11/class_support.h +++ b/include/pybind11/class_support.h @@ -14,6 +14,11 @@ NAMESPACE_BEGIN(pybind11) NAMESPACE_BEGIN(detail) +inline PyTypeObject *type_incref(PyTypeObject *type) { + Py_INCREF(type); + return type; +} + #if !defined(PYPY_VERSION) /// `pybind11_static_property.__get__()`: Always pass the class instead of the instance. @@ -49,7 +54,7 @@ inline PyTypeObject *make_static_property_type() { auto type = &heap_type->ht_type; type->tp_name = name; - type->tp_base = &PyProperty_Type; + type->tp_base = type_incref(&PyProperty_Type); type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE; type->tp_descr_get = pybind11_static_get; type->tp_descr_set = pybind11_static_set; @@ -162,7 +167,7 @@ inline PyTypeObject* make_default_metaclass() { auto type = &heap_type->ht_type; type->tp_name = name; - type->tp_base = &PyType_Type; + type->tp_base = type_incref(&PyType_Type); type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE; type->tp_setattro = pybind11_meta_setattro; @@ -361,7 +366,7 @@ inline PyObject *make_object_base_type(PyTypeObject *metaclass) { auto type = &heap_type->ht_type; type->tp_name = name; - type->tp_base = &PyBaseObject_Type; + type->tp_base = type_incref(&PyBaseObject_Type); type->tp_basicsize = static_cast(sizeof(instance)); type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE; @@ -552,7 +557,7 @@ inline PyObject* make_new_python_type(const type_record &rec) { auto type = &heap_type->ht_type; type->tp_name = strdup(full_name.c_str()); type->tp_doc = tp_doc; - type->tp_base = (PyTypeObject *) handle(base).inc_ref().ptr(); + type->tp_base = type_incref((PyTypeObject *)base); type->tp_basicsize = static_cast(sizeof(instance)); if (bases.size() > 0) type->tp_bases = bases.release().ptr();