Uh oh!
There was an error while loading. Please reload this page.
Add check for matching holder_type when inheriting - #588
Conversation
dean0x7d
commented
Jan 8, 2017
I think the test could be simplified so it doesn't require a separate module. It should be possible to pack up everything into a function within the existing test module. Something like: m.def("test_matching_holder_type", []() {
structBase { };
structDerived : Base { };
try {
py::class_<Base>(m, "Base");
py::class_<Derived, std::shared_ptr<Derived>, Base>(m, "Derived")
.def(py::init<>());
} catch (std::runtime_error &) {
returntrue;
}
returnfalse;
});asserttest_matching_holder_type() isTrueIt might be possible to simplify template <typename... Ts>
structvoid_holder<std::unique_ptr<Ts...>> {
using type = std::unique_ptr<void>;
};where the tinfo->void_holder_type = &typeid(detail::void_holder<holder_type>::type);A more generic approach for template <typename T, typenameSFINAE = void>
structvoid_holder {
using type = void;
}template <typename...> usingvoid_t = void;
template <template<typename...> classHolder, typename... Ts>
structvoid_holder<Holder<Ts...>, void_t<Holder<void>>> {
using type = Holder<void>;
};The |
wjakob
commented
Jan 8, 2017
+1 for the single module approach proposed by @dean0x7d. FWIW I think that storing a full type ID is overkill. I suggest to record a single |
pschella
commented
Jan 8, 2017
Thanks for the feedback. I pushed a simplified version. |
pschella
commented
Jan 8, 2017
That is why it was variadic, but I agree this is better. I'll make the change. |
pschella
commented
Jan 8, 2017
Wondering if we should split the error reporting telling which one has non-default holder type? |
pschella
commented
Jan 8, 2017
I split it up. Easier to debug. |
| /// Is the default (unique_ptr) holder type used? | ||
| bool default_holder : 1; | ||
| PYBIND11_NOINLINE void add_base(const std::type_info *base, void *(*caster)(void *), const bool check_holder_type = false) { |
There was a problem hiding this comment.
Why is the check_holder_type parameter needed?
| py::class_<Base>(m, "Base"); | ||
| py::class_<Derived, std::shared_ptr<Derived>, Base>(m, "Derived") | ||
| .def(py::init<>()); | ||
| } |
There was a problem hiding this comment.
Unless I'm missing something, the second test is going to be skipped completely because the first one throws. Consider separate functions.
Also, .def(py::init<>()) is probably not needed for the test.
| .def(py::init<>()); | ||
| } | ||
| } catch (std::runtime_error &) { | ||
| return true; |
There was a problem hiding this comment.
Sorry, I need to revise my original suggestion a bit. It might be nicer to catch the exception in Python in order to also check that the correct exception was thrown.
m.def("test_matching_holder_type", []() {
structBase { };
structDerived : Base { };
py::class_<Base>(m, "Base");
py::class_<Derived, std::shared_ptr<Derived>, Base>(m, "Derived");
});withpytest.raises(RuntimeError) asexcinfo:
test_matching_holder_type()
assertstr(excinfo.value) =="generic_type: ..."pschella
commented
Jan 9, 2017
I followed the suggestions from @dean0x7d to clean things up a bit more. Please let me know if I should squash the commits into one. |
dean0x7d
commented
Jan 10, 2017
There are some weird failures on AppVeyor. It may have to do with the uninitialized There are also some minor style issues. See the log on Travis. |
7333402 to
38cf38dComparepschella
commented
Jan 17, 2017
Changes implemented and commits squashed. |
wjakob
commented
Jan 31, 2017
Looks great -- thank you! |
Instead of a segfault. Fixespybind#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 pybind#588 established for inheritance.
One frequently encountered source of errors are mismatching holder types between bases and derived classes. If either the base has
unique_ptrholder type and the derived classshared_ptr(or vice versa) a segfault results.Tracking holder types for all classes in a large codebase can be cumbersome and error prone.
This pull request is an example of how import-time checks for matching holder types can be added. I welcome your comments.