Skip to content

Commit 719f9f1

Browse files
committed
handle inconsistent holder types
1 parent c9fee1d commit 719f9f1

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
@@ -231,6 +231,7 @@ struct type_record {
231231

232232
// Pointer to RTTI type_info data structure
233233
const std::type_info *type = nullptr;
234+
const std::type_info *holder_type = nullptr;
234235

235236
/// How large is the underlying C++ type?
236237
size_t type_size = 0;

include/pybind11/cast.h

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

911-
static handle cast_holder(const itype *src, const void *holder) {
911+
static handle cast_holder(const itype *src, const void *holder, const std::type_info &holder_type) {
912912
auto st = src_and_type(src);
913+
if (!same_type(*st.second->holder_type, holder_type))
914+
throw cast_error(std::string("Unexpected holder type: ") + holder_type.name() + ", expected: " + st.second->holder_type->name());
913915
return type_caster_generic::cast(
914916
st.first, return_value_policy::take_ownership, {}, st.second,
915917
nullptr, nullptr, holder);
@@ -1516,7 +1518,7 @@ struct copyable_holder_caster : public type_caster_base<type> {
15161518

15171519
static handle cast(const holder_type &src, return_value_policy, handle) {
15181520
const auto *ptr = holder_helper<holder_type>::get(src);
1519-
return type_caster_base<type>::cast_holder(ptr, &src);
1521+
return type_caster_base<type>::cast_holder(ptr, std::addressof(src), typeid(holder_type));
15201522
}
15211523

15221524
protected:
@@ -1528,6 +1530,8 @@ struct copyable_holder_caster : public type_caster_base<type> {
15281530

15291531
bool load_value(value_and_holder &&v_h) {
15301532
if (v_h.holder_constructed()) {
1533+
if (!same_type(*typeinfo->holder_type, typeid(holder_type)))
1534+
throw cast_error(std::string("Unexpected holder type: ") + typeid(holder_type).name() + ", expected: " + typeinfo->holder_type->name());
15311535
value = v_h.value_ptr();
15321536
holder = v_h.template holder<holder_type>();
15331537
return true;
@@ -1574,7 +1578,7 @@ struct move_only_holder_caster {
15741578

15751579
static handle cast(holder_type &&src, return_value_policy, handle) {
15761580
auto *ptr = holder_helper<holder_type>::get(src);
1577-
return type_caster_base<type>::cast_holder(ptr, std::addressof(src));
1581+
return type_caster_base<type>::cast_holder(ptr, std::addressof(src), typeid(holder_type));
15781582
}
15791583
static constexpr auto name = type_caster_base<type>::name;
15801584
};

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
@@ -1042,6 +1042,7 @@ class generic_type : public object {
10421042
auto *tinfo = new detail::type_info();
10431043
tinfo->type = (PyTypeObject *) m_ptr;
10441044
tinfo->cpptype = rec.type;
1045+
tinfo->holder_type = rec.holder_type;
10451046
tinfo->type_size = rec.type_size;
10461047
tinfo->type_align = rec.type_align;
10471048
tinfo->operator_new = rec.operator_new;
@@ -1225,6 +1226,7 @@ class class_ : public detail::generic_type {
12251226
record.scope = scope;
12261227
record.name = name;
12271228
record.type = &typeid(type);
1229+
record.holder_type = &typeid(holder_type);
12281230
record.type_size = sizeof(conditional_t<has_alias, type_alias, type>);
12291231
record.type_align = alignof(conditional_t<has_alias, type_alias, type>&);
12301232
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
@@ -120,7 +120,7 @@ TEST_SUBMODULE(smart_ptr, m) {
120120
py::implicitly_convertible<py::int_, MyObject1>();
121121

122122
m.def("make_object_1", []() -> Object * { return new MyObject1(1); });
123-
m.def("make_object_2", []() -> ref<Object> { return new MyObject1(2); });
123+
m.def("make_object_2", []() -> ref<MyObject1> { return new MyObject1(2); });
124124
m.def("make_myobject1_1", []() -> MyObject1 * { return new MyObject1(4); });
125125
m.def("make_myobject1_2", []() -> ref<MyObject1> { return new MyObject1(5); });
126126
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
@@ -70,7 +70,7 @@ def test_smart_ptr(capture):
7070
assert cstats.alive() == 1
7171
o = None
7272
assert cstats.alive() == 0
73-
assert cstats.values() == ["MyObject2[8]", "MyObject2[6]", "MyObject2[7]"]
73+
assert cstats.values() == ["MyObject2[8]", "MyObject2[6]", "MyObject2[7]", "MyObject2[9]"]
7474
assert cstats.default_constructions == 0
7575
assert cstats.copy_constructions == 0
7676
# assert cstats.move_constructions >= 0 # Doesn't invoke any

0 commit comments

Comments
 (0)