Skip to content

Commit

Permalink
handle inconsistent holder types
Browse files Browse the repository at this point in the history
  • Loading branch information
rhaschke committed Jan 2, 2020
1 parent eec0993 commit fccb0fc
Show file tree
Hide file tree
Showing 6 changed files with 14 additions and 6 deletions.
1 change: 1 addition & 0 deletions include/pybind11/attr.h
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ struct type_record {

// Pointer to RTTI type_info data structure
const std::type_info *type = nullptr;
const std::type_info *holder_type = nullptr;

/// How large is the underlying C++ type?
size_t type_size = 0;
Expand Down
10 changes: 7 additions & 3 deletions include/pybind11/cast.h
Original file line number Diff line number Diff line change
Expand Up @@ -902,8 +902,10 @@ template <typename type> class type_caster_base : public type_caster_generic {
make_copy_constructor(src), make_move_constructor(src));
}

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

static handle cast(const holder_type &src, return_value_policy, handle) {
const auto *ptr = holder_helper<holder_type>::get(src);
return type_caster_base<type>::cast_holder(ptr, &src);
return type_caster_base<type>::cast_holder(ptr, std::addressof(src), typeid(holder_type));
}

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

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

static handle cast(holder_type &&src, return_value_policy, handle) {
auto *ptr = holder_helper<holder_type>::get(src);
return type_caster_base<type>::cast_holder(ptr, std::addressof(src));
return type_caster_base<type>::cast_holder(ptr, std::addressof(src), typeid(holder_type));
}
static constexpr auto name = type_caster_base<type>::name;
};
Expand Down
3 changes: 2 additions & 1 deletion include/pybind11/detail/internals.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ struct internals {
struct type_info {
PyTypeObject *type;
const std::type_info *cpptype;
const std::type_info *holder_type = nullptr;
size_t type_size, type_align, holder_size_in_ptrs;
void *(*operator_new)(size_t);
void (*init_instance)(instance *, const void *);
Expand All @@ -150,7 +151,7 @@ struct type_info {
};

/// Tracks the `internals` and `type_info` ABI version independent of the main library version
#define PYBIND11_INTERNALS_VERSION 4
#define PYBIND11_INTERNALS_VERSION 5

/// On MSVC, debug and release builds are not ABI-compatible!
#if defined(_MSC_VER) && defined(_DEBUG)
Expand Down
2 changes: 2 additions & 0 deletions include/pybind11/pybind11.h
Original file line number Diff line number Diff line change
Expand Up @@ -904,6 +904,7 @@ class generic_type : public object {
auto *tinfo = new detail::type_info();
tinfo->type = (PyTypeObject *) m_ptr;
tinfo->cpptype = rec.type;
tinfo->holder_type = rec.holder_type;
tinfo->type_size = rec.type_size;
tinfo->type_align = rec.type_align;
tinfo->operator_new = rec.operator_new;
Expand Down Expand Up @@ -1080,6 +1081,7 @@ class class_ : public detail::generic_type {
record.scope = scope;
record.name = name;
record.type = &typeid(type);
record.holder_type = &typeid(holder_type);
record.type_size = sizeof(conditional_t<has_alias, type_alias, type>);
record.type_align = alignof(conditional_t<has_alias, type_alias, type>&);
record.holder_size = sizeof(holder_type);
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 @@ -119,7 +119,7 @@ TEST_SUBMODULE(smart_ptr, m) {
py::implicitly_convertible<py::int_, MyObject1>();

m.def("make_object_1", []() -> Object * { return new MyObject1(1); });
m.def("make_object_2", []() -> ref<Object> { return new MyObject1(2); });
m.def("make_object_2", []() -> ref<MyObject1> { return new MyObject1(2); });
m.def("make_myobject1_1", []() -> MyObject1 * { return new MyObject1(4); });
m.def("make_myobject1_2", []() -> ref<MyObject1> { return new MyObject1(5); });
m.def("print_object_1", [](const Object *obj) { py::print(obj->toString()); });
Expand Down
2 changes: 1 addition & 1 deletion tests/test_smart_ptr.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ def test_smart_ptr(capture):
assert cstats.alive() == 1
o = None
assert cstats.alive() == 0
assert cstats.values() == ['MyObject2[8]', 'MyObject2[6]', 'MyObject2[7]']
assert cstats.values() == ['MyObject2[8]', 'MyObject2[6]', 'MyObject2[7]', 'MyObject2[9]']
assert cstats.default_constructions == 0
assert cstats.copy_constructions == 0
# assert cstats.move_constructions >= 0 # Doesn't invoke any
Expand Down

0 comments on commit fccb0fc

Please sign in to comment.