Skip to content

Commit fccb0fc

Browse files
committed
handle inconsistent holder types
1 parent eec0993 commit fccb0fc

File tree

6 files changed

+14
-6
lines changed

6 files changed

+14
-6
lines changed

include/pybind11/attr.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@ struct type_record {
211211

212212
// Pointer to RTTI type_info data structure
213213
const std::type_info *type = nullptr;
214+
const std::type_info *holder_type = nullptr;
214215

215216
/// How large is the underlying C++ type?
216217
size_t type_size = 0;

include/pybind11/cast.h

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -902,8 +902,10 @@ template <typename type> class type_caster_base : public type_caster_generic {
902902
make_copy_constructor(src), make_move_constructor(src));
903903
}
904904

905-
static handle cast_holder(const itype *src, const void *holder) {
905+
static handle cast_holder(const itype *src, const void *holder, const std::type_info &holder_type) {
906906
auto st = src_and_type(src);
907+
if (!same_type(*st.second->holder_type, holder_type))
908+
throw cast_error(std::string("Unexpected holder type: ") + holder_type.name() + ", expected: " + st.second->holder_type->name());
907909
return type_caster_generic::cast(
908910
st.first, return_value_policy::take_ownership, {}, st.second,
909911
nullptr, nullptr, holder);
@@ -1505,7 +1507,7 @@ struct copyable_holder_caster : public type_caster_base<type> {
15051507

15061508
static handle cast(const holder_type &src, return_value_policy, handle) {
15071509
const auto *ptr = holder_helper<holder_type>::get(src);
1508-
return type_caster_base<type>::cast_holder(ptr, &src);
1510+
return type_caster_base<type>::cast_holder(ptr, std::addressof(src), typeid(holder_type));
15091511
}
15101512

15111513
protected:
@@ -1517,6 +1519,8 @@ struct copyable_holder_caster : public type_caster_base<type> {
15171519

15181520
bool load_value(value_and_holder &&v_h) {
15191521
if (v_h.holder_constructed()) {
1522+
if (!same_type(*typeinfo->holder_type, typeid(holder_type)))
1523+
throw cast_error(std::string("Unexpected holder type: ") + typeid(holder_type).name() + ", expected: " + typeinfo->holder_type->name());
15201524
value = v_h.value_ptr();
15211525
holder = v_h.template holder<holder_type>();
15221526
return true;
@@ -1563,7 +1567,7 @@ struct move_only_holder_caster {
15631567

15641568
static handle cast(holder_type &&src, return_value_policy, handle) {
15651569
auto *ptr = holder_helper<holder_type>::get(src);
1566-
return type_caster_base<type>::cast_holder(ptr, std::addressof(src));
1570+
return type_caster_base<type>::cast_holder(ptr, std::addressof(src), typeid(holder_type));
15671571
}
15681572
static constexpr auto name = type_caster_base<type>::name;
15691573
};

include/pybind11/detail/internals.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ struct internals {
128128
struct type_info {
129129
PyTypeObject *type;
130130
const std::type_info *cpptype;
131+
const std::type_info *holder_type = nullptr;
131132
size_t type_size, type_align, holder_size_in_ptrs;
132133
void *(*operator_new)(size_t);
133134
void (*init_instance)(instance *, const void *);
@@ -150,7 +151,7 @@ struct type_info {
150151
};
151152

152153
/// Tracks the `internals` and `type_info` ABI version independent of the main library version
153-
#define PYBIND11_INTERNALS_VERSION 4
154+
#define PYBIND11_INTERNALS_VERSION 5
154155

155156
/// On MSVC, debug and release builds are not ABI-compatible!
156157
#if defined(_MSC_VER) && defined(_DEBUG)

include/pybind11/pybind11.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -904,6 +904,7 @@ class generic_type : public object {
904904
auto *tinfo = new detail::type_info();
905905
tinfo->type = (PyTypeObject *) m_ptr;
906906
tinfo->cpptype = rec.type;
907+
tinfo->holder_type = rec.holder_type;
907908
tinfo->type_size = rec.type_size;
908909
tinfo->type_align = rec.type_align;
909910
tinfo->operator_new = rec.operator_new;
@@ -1080,6 +1081,7 @@ class class_ : public detail::generic_type {
10801081
record.scope = scope;
10811082
record.name = name;
10821083
record.type = &typeid(type);
1084+
record.holder_type = &typeid(holder_type);
10831085
record.type_size = sizeof(conditional_t<has_alias, type_alias, type>);
10841086
record.type_align = alignof(conditional_t<has_alias, type_alias, type>&);
10851087
record.holder_size = sizeof(holder_type);

tests/test_smart_ptr.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ TEST_SUBMODULE(smart_ptr, m) {
119119
py::implicitly_convertible<py::int_, MyObject1>();
120120

121121
m.def("make_object_1", []() -> Object * { return new MyObject1(1); });
122-
m.def("make_object_2", []() -> ref<Object> { return new MyObject1(2); });
122+
m.def("make_object_2", []() -> ref<MyObject1> { return new MyObject1(2); });
123123
m.def("make_myobject1_1", []() -> MyObject1 * { return new MyObject1(4); });
124124
m.def("make_myobject1_2", []() -> ref<MyObject1> { return new MyObject1(5); });
125125
m.def("print_object_1", [](const Object *obj) { py::print(obj->toString()); });

tests/test_smart_ptr.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ def test_smart_ptr(capture):
5959
assert cstats.alive() == 1
6060
o = None
6161
assert cstats.alive() == 0
62-
assert cstats.values() == ['MyObject2[8]', 'MyObject2[6]', 'MyObject2[7]']
62+
assert cstats.values() == ['MyObject2[8]', 'MyObject2[6]', 'MyObject2[7]', 'MyObject2[9]']
6363
assert cstats.default_constructions == 0
6464
assert cstats.copy_constructions == 0
6565
# assert cstats.move_constructions >= 0 # Doesn't invoke any

0 commit comments

Comments
 (0)