diff --git a/include/pybind11/detail/classh_type_casters.h b/include/pybind11/detail/classh_type_casters.h index b6a0cca14..5d838c3b1 100644 --- a/include/pybind11/detail/classh_type_casters.h +++ b/include/pybind11/detail/classh_type_casters.h @@ -231,29 +231,42 @@ struct smart_holder_type_caster_load { return true; } - T *loaded_as_raw_ptr_unowned() { - void *void_ptr = loaded_smhldr_ptr->as_raw_ptr_unowned(); - if (load_impl.loaded_v_h_cpptype == nullptr || load_impl.reinterpret_cast_deemed_ok - || load_impl.implicit_cast == nullptr) { - return static_cast(void_ptr); + T *convert_type(void *void_ptr) { + if (void_ptr != nullptr && load_impl.loaded_v_h_cpptype != nullptr + && !load_impl.reinterpret_cast_deemed_ok && load_impl.implicit_cast != nullptr) { + void_ptr = load_impl.implicit_cast(void_ptr); } - void *implicit_casted = load_impl.implicit_cast(void_ptr); - return static_cast(implicit_casted); + return static_cast(void_ptr); + } + + T *loaded_as_raw_ptr_unowned() { + return convert_type(loaded_smhldr_ptr->as_raw_ptr_unowned()); } std::shared_ptr loaded_as_shared_ptr() { - T *raw_ptr = loaded_as_raw_ptr_unowned(); - return std::shared_ptr(loaded_smhldr_ptr->as_shared_ptr(), raw_ptr); + std::shared_ptr void_ptr = loaded_smhldr_ptr->as_shared_ptr(); + return std::shared_ptr(void_ptr, convert_type(void_ptr.get())); } std::unique_ptr loaded_as_unique_ptr() { - void *value_void_ptr = load_impl.loaded_v_h.value_ptr(); - auto unq_ptr = loaded_smhldr_ptr->as_unique_ptr(); + loaded_smhldr_ptr->ensure_can_release_ownership(); + auto raw_void_ptr = loaded_smhldr_ptr->as_raw_ptr_unowned(); + // MISSING: Safety checks for type conversions + // (T must be polymorphic or meet certain other conditions). + T *raw_type_ptr = convert_type(raw_void_ptr); + + // Critical transfer-of-ownership section. This must stay together. + loaded_smhldr_ptr->release_ownership(); + auto result = std::unique_ptr(raw_type_ptr); + + void *value_void_ptr + = load_impl.loaded_v_h.value_ptr(); // Expected to be identical to raw_void_ptr. load_impl.loaded_v_h.holder().~holder_type(); load_impl.loaded_v_h.set_holder_constructed(false); load_impl.loaded_v_h.value_ptr() = nullptr; deregister_instance(load_impl.loaded_v_h.inst, value_void_ptr, load_impl.loaded_v_h.type); - return unq_ptr; + + return result; } protected: diff --git a/include/pybind11/smart_holder_poc.h b/include/pybind11/smart_holder_poc.h index 58e4bd587..d0a8ce368 100644 --- a/include/pybind11/smart_holder_poc.h +++ b/include/pybind11/smart_holder_poc.h @@ -186,13 +186,22 @@ struct smart_holder { return hld; } - template - T *as_raw_ptr_release_ownership(const char *context = "as_raw_ptr_release_ownership") { + void ensure_can_release_ownership(const char *context = "ensure_can_release_ownership") { ensure_vptr_is_using_builtin_delete(context); ensure_use_count_1(context); - T *raw_ptr = as_raw_ptr_unowned(); + } + + // Caller is responsible for calling ensure_can_release_ownership(). + void release_ownership() { *vptr_deleter_armed_flag_ptr = false; vptr.reset(); + } + + template + T *as_raw_ptr_release_ownership(const char *context = "as_raw_ptr_release_ownership") { + ensure_can_release_ownership(context); + T *raw_ptr = as_raw_ptr_unowned(); + release_ownership(); return raw_ptr; }