Skip to content

Commit

Permalink
Correctly handle mismatched holders in function arguments
Browse files Browse the repository at this point in the history
  • Loading branch information
rhaschke committed Nov 6, 2020
1 parent 0fe5697 commit 6360006
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 19 deletions.
40 changes: 23 additions & 17 deletions include/pybind11/cast.h
Original file line number Diff line number Diff line change
Expand Up @@ -1491,6 +1491,27 @@ struct holder_helper {
static auto get(const T &p) -> decltype(p.get()) { return p.get(); }
};

template <typename holder>
void check_for_holder_mismatch_impl() {
using iholder = intrinsic_t<holder>;
using base_type = decltype(*holder_helper<iholder>::get(std::declval<iholder>()));
auto &holder_typeinfo = typeid(iholder);
auto ins = get_internals().holders_seen.emplace(typeid(base_type), &holder_typeinfo);

auto debug = type_id<base_type>();
if (!ins.second && !same_type(*ins.first->second, holder_typeinfo)) {
#ifdef NDEBUG
pybind11_fail("Mismatched holders detected (compile in debug mode for details)");
#else
std::string seen_holder_name(ins.first->second->name());
detail::clean_type_id(seen_holder_name);
pybind11_fail("Mismatched holders detected: "
" attempting to use holder type " + type_id<iholder>() + ", but " + type_id<base_type>() +
" was already seen using holder type " + seen_holder_name);
#endif
}
}

/// Type caster for holder types like std::shared_ptr, etc.
template <typename type, typename holder_type>
struct copyable_holder_caster : public type_caster_base<type> {
Expand Down Expand Up @@ -1524,6 +1545,7 @@ struct copyable_holder_caster : public type_caster_base<type> {
void check_holder_compat() {
if (typeinfo->default_holder)
throw cast_error("Unable to load a custom holder type from a default-holder instance");
check_for_holder_mismatch_impl<holder_type>();
}

bool load_value(value_and_holder &&v_h) {
Expand Down Expand Up @@ -1615,23 +1637,7 @@ template <typename holder>
void check_for_holder_mismatch(enable_if_t<!is_holder<holder>::value, int> = 0) {}
template <typename holder>
void check_for_holder_mismatch(enable_if_t<is_holder<holder>::value, int> = 0) {
using iholder = intrinsic_t<holder>;
using base_type = decltype(*holder_helper<iholder>::get(std::declval<iholder>()));
auto &holder_typeinfo = typeid(iholder);
auto ins = get_internals().holders_seen.emplace(typeid(base_type), &holder_typeinfo);

auto debug = type_id<base_type>();
if (!ins.second && !same_type(*ins.first->second, holder_typeinfo)) {
#ifdef NDEBUG
pybind11_fail("Mismatched holders detected (compile in debug mode for details)");
#else
std::string seen_holder_name(ins.first->second->name());
detail::clean_type_id(seen_holder_name);
pybind11_fail("Mismatched holders detected: "
" attempting to use holder type " + type_id<iholder>() + ", but " + type_id<base_type>() +
" was already seen using holder type " + seen_holder_name);
#endif
}
check_for_holder_mismatch_impl<holder>();
}

template <typename T> struct handle_type_name { static constexpr auto name = _<T>(); };
Expand Down
2 changes: 1 addition & 1 deletion tests/test_smart_ptr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,6 @@ TEST_SUBMODULE(smart_ptr, m) {
// Fails: `return_shared' already returned this via shared_ptr holder
py::class_<HeldByUnique>(m, "HeldByUnique");
});
// segfaults, because std::shared_ptr<MyObject5> is interpreted as huge_unique_ptr<MyObject5>
// Fails: MyObject5 was declared with huge_unique_ptr as holder instead of shared_ptr
m.def("consume_mismatching_holder", [](std::shared_ptr<MyObject5> o) { return o->value; });
}
4 changes: 3 additions & 1 deletion tests/test_smart_ptr.py
Original file line number Diff line number Diff line change
Expand Up @@ -320,4 +320,6 @@ def test_holder_mismatch():
m.register_mismatch_class(m)
assert "Mismatched holders detected" in str(excinfo)

assert m.consume_mismatching_holder(m.MyObject5(42)) == 42
with pytest.raises(RuntimeError) as excinfo:
m.consume_mismatching_holder(m.MyObject5(42))
assert "Mismatched holders detected" in str(excinfo)

0 comments on commit 6360006

Please sign in to comment.