Skip to content

Commit 6360006

Browse files
committed
Correctly handle mismatched holders in function arguments
1 parent 0fe5697 commit 6360006

File tree

3 files changed

+27
-19
lines changed

3 files changed

+27
-19
lines changed

include/pybind11/cast.h

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1491,6 +1491,27 @@ struct holder_helper {
14911491
static auto get(const T &p) -> decltype(p.get()) { return p.get(); }
14921492
};
14931493

1494+
template <typename holder>
1495+
void check_for_holder_mismatch_impl() {
1496+
using iholder = intrinsic_t<holder>;
1497+
using base_type = decltype(*holder_helper<iholder>::get(std::declval<iholder>()));
1498+
auto &holder_typeinfo = typeid(iholder);
1499+
auto ins = get_internals().holders_seen.emplace(typeid(base_type), &holder_typeinfo);
1500+
1501+
auto debug = type_id<base_type>();
1502+
if (!ins.second && !same_type(*ins.first->second, holder_typeinfo)) {
1503+
#ifdef NDEBUG
1504+
pybind11_fail("Mismatched holders detected (compile in debug mode for details)");
1505+
#else
1506+
std::string seen_holder_name(ins.first->second->name());
1507+
detail::clean_type_id(seen_holder_name);
1508+
pybind11_fail("Mismatched holders detected: "
1509+
" attempting to use holder type " + type_id<iholder>() + ", but " + type_id<base_type>() +
1510+
" was already seen using holder type " + seen_holder_name);
1511+
#endif
1512+
}
1513+
}
1514+
14941515
/// Type caster for holder types like std::shared_ptr, etc.
14951516
template <typename type, typename holder_type>
14961517
struct copyable_holder_caster : public type_caster_base<type> {
@@ -1524,6 +1545,7 @@ struct copyable_holder_caster : public type_caster_base<type> {
15241545
void check_holder_compat() {
15251546
if (typeinfo->default_holder)
15261547
throw cast_error("Unable to load a custom holder type from a default-holder instance");
1548+
check_for_holder_mismatch_impl<holder_type>();
15271549
}
15281550

15291551
bool load_value(value_and_holder &&v_h) {
@@ -1615,23 +1637,7 @@ template <typename holder>
16151637
void check_for_holder_mismatch(enable_if_t<!is_holder<holder>::value, int> = 0) {}
16161638
template <typename holder>
16171639
void check_for_holder_mismatch(enable_if_t<is_holder<holder>::value, int> = 0) {
1618-
using iholder = intrinsic_t<holder>;
1619-
using base_type = decltype(*holder_helper<iholder>::get(std::declval<iholder>()));
1620-
auto &holder_typeinfo = typeid(iholder);
1621-
auto ins = get_internals().holders_seen.emplace(typeid(base_type), &holder_typeinfo);
1622-
1623-
auto debug = type_id<base_type>();
1624-
if (!ins.second && !same_type(*ins.first->second, holder_typeinfo)) {
1625-
#ifdef NDEBUG
1626-
pybind11_fail("Mismatched holders detected (compile in debug mode for details)");
1627-
#else
1628-
std::string seen_holder_name(ins.first->second->name());
1629-
detail::clean_type_id(seen_holder_name);
1630-
pybind11_fail("Mismatched holders detected: "
1631-
" attempting to use holder type " + type_id<iholder>() + ", but " + type_id<base_type>() +
1632-
" was already seen using holder type " + seen_holder_name);
1633-
#endif
1634-
}
1640+
check_for_holder_mismatch_impl<holder>();
16351641
}
16361642

16371643
template <typename T> struct handle_type_name { static constexpr auto name = _<T>(); };

tests/test_smart_ptr.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,6 @@ TEST_SUBMODULE(smart_ptr, m) {
382382
// Fails: `return_shared' already returned this via shared_ptr holder
383383
py::class_<HeldByUnique>(m, "HeldByUnique");
384384
});
385-
// segfaults, because std::shared_ptr<MyObject5> is interpreted as huge_unique_ptr<MyObject5>
385+
// Fails: MyObject5 was declared with huge_unique_ptr as holder instead of shared_ptr
386386
m.def("consume_mismatching_holder", [](std::shared_ptr<MyObject5> o) { return o->value; });
387387
}

tests/test_smart_ptr.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -320,4 +320,6 @@ def test_holder_mismatch():
320320
m.register_mismatch_class(m)
321321
assert "Mismatched holders detected" in str(excinfo)
322322

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

0 commit comments

Comments
 (0)