fix rare GC issue during type creation (fixes #277)

This commit is contained in:
Wenzel Jakob 2016-07-11 23:40:28 +02:00
parent c075997617
commit dc4d7493b3
2 changed files with 48 additions and 35 deletions

View File

@ -13,9 +13,10 @@ Breaking changes queued for v2.0.0 (Not yet released)
* Remove ``handle.call()`` method * Remove ``handle.call()`` method
1.9.0 (Not yet released) 1.8.1 (July 12, 2016)
---------------------- ----------------------
* Queued changes: ``py::eval*``, map indexing suite, documentation for indexing suites. * Fixed a rare but potentially very severe issue when the garbage collector ran
during pybind11 type creation.
1.8.0 (June 14, 2016) 1.8.0 (June 14, 2016)
---------------------- ----------------------

View File

@ -525,8 +525,40 @@ protected:
pybind11_fail("generic_type: type \"" + std::string(rec->name) + pybind11_fail("generic_type: type \"" + std::string(rec->name) +
"\" is already registered!"); "\" is already registered!");
object type_holder(PyType_Type.tp_alloc(&PyType_Type, 0), false);
object name(PYBIND11_FROM_STRING(rec->name), false); object name(PYBIND11_FROM_STRING(rec->name), false);
object scope_module;
if (rec->scope) {
scope_module = (object) rec->scope.attr("__module__");
if (!scope_module)
scope_module = (object) rec->scope.attr("__name__");
}
#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 3
/* Qualified names for Python >= 3.3 */
object scope_qualname;
if (rec->scope)
scope_qualname = (object) rec->scope.attr("__qualname__");
object ht_qualname;
if (scope_qualname) {
ht_qualname = object(PyUnicode_FromFormat(
"%U.%U", scope_qualname.ptr(), name.ptr()), false);
} else {
ht_qualname = name;
}
#endif
std::string full_name = (scope_module ? ((std::string) scope_module.str() + "." + rec->name)
: std::string(rec->name));
char *tp_doc = nullptr;
if (rec->doc) {
/* Allocate memory for docstring (using PyObject_MALLOC, since
Python will free this later on) */
size_t size = strlen(rec->doc) + 1;
tp_doc = (char *) PyObject_MALLOC(size);
memcpy((void *) tp_doc, rec->doc, size);
}
object type_holder(PyType_Type.tp_alloc(&PyType_Type, 0), false);
auto type = (PyHeapTypeObject*) type_holder.ptr(); auto type = (PyHeapTypeObject*) type_holder.ptr();
if (!type_holder || !name) if (!type_holder || !name)
@ -540,36 +572,18 @@ protected:
internals.registered_types_cpp[tindex] = tinfo; internals.registered_types_cpp[tindex] = tinfo;
internals.registered_types_py[type] = tinfo; internals.registered_types_py[type] = tinfo;
object scope_module;
if (rec->scope) {
scope_module = (object) rec->scope.attr("__module__");
if (!scope_module)
scope_module = (object) rec->scope.attr("__name__");
}
std::string full_name = (scope_module ? ((std::string) scope_module.str() + "." + rec->name)
: std::string(rec->name));
/* Basic type attributes */ /* Basic type attributes */
type->ht_type.tp_name = strdup(full_name.c_str()); type->ht_type.tp_name = strdup(full_name.c_str());
type->ht_type.tp_basicsize = (ssize_t) rec->instance_size; type->ht_type.tp_basicsize = (ssize_t) rec->instance_size;
type->ht_type.tp_base = (PyTypeObject *) rec->base_handle.ptr(); type->ht_type.tp_base = (PyTypeObject *) rec->base_handle.ptr();
rec->base_handle.inc_ref(); rec->base_handle.inc_ref();
#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 3
/* Qualified names for Python >= 3.3 */
object scope_qualname;
if (rec->scope)
scope_qualname = (object) rec->scope.attr("__qualname__");
if (scope_qualname) {
type->ht_qualname = PyUnicode_FromFormat(
"%U.%U", scope_qualname.ptr(), name.ptr());
} else {
type->ht_qualname = name.ptr();
name.inc_ref();
}
#endif
type->ht_name = name.release().ptr(); type->ht_name = name.release().ptr();
#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 3
type->ht_qualname = ht_qualname.release().ptr();
#endif
/* Supported protocols */ /* Supported protocols */
type->ht_type.tp_as_number = &type->as_number; type->ht_type.tp_as_number = &type->as_number;
type->ht_type.tp_as_sequence = &type->as_sequence; type->ht_type.tp_as_sequence = &type->as_sequence;
@ -590,13 +604,7 @@ protected:
#endif #endif
type->ht_type.tp_flags &= ~Py_TPFLAGS_HAVE_GC; type->ht_type.tp_flags &= ~Py_TPFLAGS_HAVE_GC;
if (rec->doc) { type->ht_type.tp_doc = tp_doc;
/* Allocate memory for docstring (using PyObject_MALLOC, since
Python will free this later on) */
size_t size = strlen(rec->doc) + 1;
type->ht_type.tp_doc = (char *) PyObject_MALLOC(size);
memcpy((void *) type->ht_type.tp_doc, rec->doc, size);
}
if (PyType_Ready(&type->ht_type) < 0) if (PyType_Ready(&type->ht_type) < 0)
pybind11_fail("generic_type: PyType_Ready failed!"); pybind11_fail("generic_type: PyType_Ready failed!");
@ -620,17 +628,21 @@ protected:
if (ob_type == &PyType_Type) { if (ob_type == &PyType_Type) {
std::string name_ = std::string(ht_type.tp_name) + "__Meta"; std::string name_ = std::string(ht_type.tp_name) + "__Meta";
object type_holder(PyType_Type.tp_alloc(&PyType_Type, 0), false); #if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 3
object ht_qualname(PyUnicode_FromFormat(
"%U__Meta", ((object) attr("__qualname__")).ptr()), false);
#endif
object name(PYBIND11_FROM_STRING(name_.c_str()), false); object name(PYBIND11_FROM_STRING(name_.c_str()), false);
object type_holder(PyType_Type.tp_alloc(&PyType_Type, 0), false);
if (!type_holder || !name) if (!type_holder || !name)
pybind11_fail("generic_type::metaclass(): unable to create type object!"); pybind11_fail("generic_type::metaclass(): unable to create type object!");
auto type = (PyHeapTypeObject*) type_holder.ptr(); auto type = (PyHeapTypeObject*) type_holder.ptr();
type->ht_name = name.release().ptr(); type->ht_name = name.release().ptr();
#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 3 #if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 3
/* Qualified names for Python >= 3.3 */ /* Qualified names for Python >= 3.3 */
type->ht_qualname = PyUnicode_FromFormat( type->ht_qualname = ht_qualname.release().ptr();
"%U__Meta", ((object) attr("__qualname__")).ptr());
#endif #endif
type->ht_type.tp_name = strdup(name_.c_str()); type->ht_type.tp_name = strdup(name_.c_str());
type->ht_type.tp_base = ob_type; type->ht_type.tp_base = ob_type;