diff --git a/include/pybind11/detail/type_caster_base.h b/include/pybind11/detail/type_caster_base.h index d4f9a41e0..f3d453014 100644 --- a/include/pybind11/detail/type_caster_base.h +++ b/include/pybind11/detail/type_caster_base.h @@ -776,6 +776,14 @@ struct load_helper : value_and_holder_helper { if (released_ptr) { return std::shared_ptr(released_ptr, type_raw_ptr); } + auto *self_life_support + = dynamic_raw_ptr_cast_if_possible(type_raw_ptr); + if (self_life_support == nullptr) { + std::shared_ptr void_shd_ptr = hld.template as_shared_ptr(); + std::shared_ptr to_be_released(void_shd_ptr, type_raw_ptr); + vptr_gd_ptr->released_ptr = to_be_released; + return to_be_released; + } std::shared_ptr to_be_released( type_raw_ptr, shared_ptr_trampoline_self_life_support(loaded_v_h.inst)); vptr_gd_ptr->released_ptr = to_be_released; diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index c84b24d3b..338a9af37 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -3416,14 +3416,23 @@ PYBIND11_NAMESPACE_END(detail) template function get_override(const T *this_ptr, const char *name) { auto *tinfo = detail::get_type_info(typeid(T)); + fflush(stderr); + printf("\nLOOOK get_override tinfo truthy = %s\n", tinfo ? "YES" : "NO"); + fflush(stdout); return tinfo ? detail::get_type_override(this_ptr, tinfo, name) : function(); } #define PYBIND11_OVERRIDE_IMPL(ret_type, cname, name, ...) \ do { \ pybind11::gil_scoped_acquire gil; \ + fflush(stderr); \ + printf("\nLOOOK BEFORE static_cast(this)\n"); \ + fflush(stdout); \ pybind11::function override \ = pybind11::get_override(static_cast(this), name); \ + fflush(stderr); \ + printf("\nLOOOK AFTER static_cast(this)\n"); \ + fflush(stdout); \ if (override) { \ auto o = override(__VA_ARGS__); \ PYBIND11_WARNING_PUSH \ diff --git a/tests/test_class_sh_trampoline_shared_ptr_cpp_arg.cpp b/tests/test_class_sh_trampoline_shared_ptr_cpp_arg.cpp index 49e1ac885..5580848c6 100644 --- a/tests/test_class_sh_trampoline_shared_ptr_cpp_arg.cpp +++ b/tests/test_class_sh_trampoline_shared_ptr_cpp_arg.cpp @@ -28,7 +28,7 @@ struct SpBase { std::shared_ptr pass_through_shd_ptr(const std::shared_ptr &obj) { return obj; } -struct PySpBase : SpBase { +struct PySpBase : SpBase, py::trampoline_self_life_support { using SpBase::SpBase; bool is_base_used() override { PYBIND11_OVERRIDE(bool, SpBase, is_base_used); } }; diff --git a/tests/test_class_sh_trampoline_weak_ptr.cpp b/tests/test_class_sh_trampoline_weak_ptr.cpp index e0036a08a..a0cd19d44 100644 --- a/tests/test_class_sh_trampoline_weak_ptr.cpp +++ b/tests/test_class_sh_trampoline_weak_ptr.cpp @@ -14,9 +14,15 @@ struct VirtBase { virtual int get_code() { return 100; } }; -struct PyVirtBase : VirtBase, py::trampoline_self_life_support { +struct PyVirtBase : VirtBase /*, py::trampoline_self_life_support */ { using VirtBase::VirtBase; int get_code() override { PYBIND11_OVERRIDE(int, VirtBase, get_code); } + + ~PyVirtBase() override { + fflush(stderr); + printf("\nLOOOK ~PyVirtBase()\n"); + fflush(stdout); + } }; struct WpOwner { @@ -34,6 +40,10 @@ private: std::weak_ptr wp; }; +std::shared_ptr pass_through_sp_VirtBase(const std::shared_ptr &sp) { + return sp; +} + } // namespace class_sh_trampoline_weak_ptr } // namespace pybind11_tests @@ -48,4 +58,6 @@ TEST_SUBMODULE(class_sh_trampoline_weak_ptr, m) { .def(py::init<>()) .def("set_wp", &WpOwner::set_wp) .def("get_code", &WpOwner::get_code); + + m.def("pass_through_sp_VirtBase", pass_through_sp_VirtBase); } diff --git a/tests/test_class_sh_trampoline_weak_ptr.py b/tests/test_class_sh_trampoline_weak_ptr.py index a60a2e7b4..784cd0178 100644 --- a/tests/test_class_sh_trampoline_weak_ptr.py +++ b/tests/test_class_sh_trampoline_weak_ptr.py @@ -1,5 +1,7 @@ from __future__ import annotations +import gc + import pytest import env @@ -20,12 +22,22 @@ def test_weak_ptr_owner(vtype, expected_code): assert obj.get_code() == expected_code wpo.set_wp(obj) - if vtype is m.VirtBase: - assert wpo.get_code() == expected_code - else: - assert wpo.get_code() == -999 # THIS NEEDS FIXING (issue #5623) + assert wpo.get_code() == expected_code del obj if env.PYPY or env.GRAALPY: pytest.skip("Cannot reliably trigger GC") assert wpo.get_code() == -999 + + +@pytest.mark.parametrize(("vtype", "expected_code"), [(m.VirtBase, 100), (PyDrvd, 200)]) +def test_pass_through_sp_VirtBase(vtype, expected_code): + obj = vtype() + ptr = m.pass_through_sp_VirtBase(obj) + print("\nLOOOK BEFORE del obj", flush=True) + del obj + print("\nLOOOK AFTER del obj", flush=True) + gc.collect() + print("\nLOOOK AFTER gc.collect()", flush=True) + assert ptr.get_code() == expected_code + print("\nLOOOK AFTER ptr.get_code()", flush=True) diff --git a/tests/test_class_sp_trampoline_weak_ptr.cpp b/tests/test_class_sp_trampoline_weak_ptr.cpp index 06250b303..a9295fcf2 100644 --- a/tests/test_class_sp_trampoline_weak_ptr.cpp +++ b/tests/test_class_sp_trampoline_weak_ptr.cpp @@ -17,6 +17,12 @@ struct VirtBase { struct PyVirtBase : VirtBase, py::trampoline_self_life_support { using VirtBase::VirtBase; int get_code() override { PYBIND11_OVERRIDE(int, VirtBase, get_code); } + + ~PyVirtBase() override { + fflush(stderr); + printf("\nLOOOK ~PyVirtBase()\n"); + fflush(stdout); + } }; struct WpOwner { @@ -48,6 +54,10 @@ private: std::shared_ptr sp; }; +std::shared_ptr pass_through_sp_VirtBase(const std::shared_ptr &sp) { + return sp; +} + } // namespace class_sp_trampoline_weak_ptr } // namespace pybind11_tests @@ -67,4 +77,6 @@ TEST_SUBMODULE(class_sp_trampoline_weak_ptr, m) { .def(py::init<>()) .def("set_sp", &SpOwner::set_sp) .def("get_code", &SpOwner::get_code); + + m.def("pass_through_sp_VirtBase", pass_through_sp_VirtBase); } diff --git a/tests/test_class_sp_trampoline_weak_ptr.py b/tests/test_class_sp_trampoline_weak_ptr.py index 5c427f980..f41eedccb 100644 --- a/tests/test_class_sp_trampoline_weak_ptr.py +++ b/tests/test_class_sp_trampoline_weak_ptr.py @@ -1,5 +1,7 @@ from __future__ import annotations +import gc + import pytest import env @@ -42,7 +44,9 @@ def test_with_sp_owner(vtype, expected_code): del obj if env.PYPY or env.GRAALPY: pytest.skip("Cannot reliably trigger GC") + print("\nLOOOK BEFORE spo.get_code() AFTER del obj", flush=True) assert spo.get_code() == 100 # Inheritance slicing (issue #1333) + print("\nLOOOK AFTER spo.get_code() AFTER del obj", flush=True) @pytest.mark.parametrize(("vtype", "expected_code"), [(m.VirtBase, 100), (PyDrvd, 200)]) @@ -67,3 +71,16 @@ def test_with_sp_and_wp_owners(vtype, expected_code): del spo assert wpo.get_code() == -999 + + +@pytest.mark.parametrize(("vtype", "expected_code"), [(m.VirtBase, 100), (PyDrvd, 200)]) +def test_pass_through_sp_VirtBase(vtype, expected_code): + obj = vtype() + ptr = m.pass_through_sp_VirtBase(obj) + print("\nLOOOK BEFORE del obj", flush=True) + del obj + print("\nLOOOK AFTER del obj", flush=True) + gc.collect() + print("\nLOOOK AFTER gc.collect()", flush=True) + assert ptr.get_code() == expected_code + print("\nLOOOK AFTER ptr.get_code()", flush=True)