Throw an exception when attempting to load an incompatible holder

Instead of a segfault. Fixes #751.

This covers the case of loading a custom holder from a default-holder
instance. Attempting to load one custom holder from a different custom
holder (i.e. not `std::unique_ptr`) yields undefined behavior, just as
#588 established for inheritance.
This commit is contained in:
Dean Moldovan 2017-03-20 21:53:24 +01:00
parent 0f5ec0a87e
commit cd3d1fc7df
3 changed files with 18 additions and 0 deletions

View File

@ -919,6 +919,9 @@ public:
return true; return true;
} }
if (typeinfo->default_holder)
throw cast_error("Unable to load a custom holder type from a default-holder instance");
if (typeinfo->simple_type) { /* Case 1: no multiple inheritance etc. involved */ if (typeinfo->simple_type) { /* Case 1: no multiple inheritance etc. involved */
/* Check if we can safely perform a reinterpret-style cast */ /* Check if we can safely perform a reinterpret-style cast */
if (PyType_IsSubtype(tobj, typeinfo->type)) if (PyType_IsSubtype(tobj, typeinfo->type))

View File

@ -265,4 +265,10 @@ test_initializer smart_ptr_and_references([](py::module &pm) {
py::class_<C, CustomUniquePtr<C>>(m, "TypeWithMoveOnlyHolder") py::class_<C, CustomUniquePtr<C>>(m, "TypeWithMoveOnlyHolder")
.def_static("make", []() { return CustomUniquePtr<C>(new C); }); .def_static("make", []() { return CustomUniquePtr<C>(new C); });
struct HeldByDefaultHolder { };
py::class_<HeldByDefaultHolder>(m, "HeldByDefaultHolder")
.def(py::init<>())
.def_static("load_shared_ptr", [](std::shared_ptr<HeldByDefaultHolder>) {});
}); });

View File

@ -211,3 +211,12 @@ def test_move_only_holder():
assert stats.alive() == 1 assert stats.alive() == 1
del a del a
assert stats.alive() == 0 assert stats.alive() == 0
def test_smart_ptr_from_default():
from pybind11_tests.smart_ptr import HeldByDefaultHolder
instance = HeldByDefaultHolder()
with pytest.raises(RuntimeError) as excinfo:
HeldByDefaultHolder.load_shared_ptr(instance)
assert "Unable to load a custom holder type from a default-holder instance" in str(excinfo)