mirror of
https://github.com/pybind/pybind11.git
synced 2026-03-14 20:27:47 +00:00
Modify py::trampoline_self_life_support semantics: if trampoline class does not inherit from this class, preserve established Inheritance Slicing behavior.
rwgk reached this point with the help of ChatGPT: * https://chatgpt.com/share/68056498-7d94-8008-8ff0-232e2aba451c The only production code change in this commit is: ``` diff --git a/include/pybind11/detail/type_caster_base.h b/include/pybind11/detail/type_caster_base.h index d4f9a41e..f3d45301 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<T>(released_ptr, type_raw_ptr); } + auto *self_life_support + = dynamic_raw_ptr_cast_if_possible<trampoline_self_life_support>(type_raw_ptr); + if (self_life_support == nullptr) { + std::shared_ptr<void> void_shd_ptr = hld.template as_shared_ptr<void>(); + std::shared_ptr<T> to_be_released(void_shd_ptr, type_raw_ptr); + vptr_gd_ptr->released_ptr = to_be_released; + return to_be_released; + } std::shared_ptr<T> to_be_released( type_raw_ptr, shared_ptr_trampoline_self_life_support(loaded_v_h.inst)); vptr_gd_ptr->released_ptr = to_be_released; ```
This commit is contained in:
@@ -776,6 +776,14 @@ struct load_helper : value_and_holder_helper {
|
||||
if (released_ptr) {
|
||||
return std::shared_ptr<T>(released_ptr, type_raw_ptr);
|
||||
}
|
||||
auto *self_life_support
|
||||
= dynamic_raw_ptr_cast_if_possible<trampoline_self_life_support>(type_raw_ptr);
|
||||
if (self_life_support == nullptr) {
|
||||
std::shared_ptr<void> void_shd_ptr = hld.template as_shared_ptr<void>();
|
||||
std::shared_ptr<T> to_be_released(void_shd_ptr, type_raw_ptr);
|
||||
vptr_gd_ptr->released_ptr = to_be_released;
|
||||
return to_be_released;
|
||||
}
|
||||
std::shared_ptr<T> to_be_released(
|
||||
type_raw_ptr, shared_ptr_trampoline_self_life_support(loaded_v_h.inst));
|
||||
vptr_gd_ptr->released_ptr = to_be_released;
|
||||
|
||||
@@ -3416,14 +3416,23 @@ PYBIND11_NAMESPACE_END(detail)
|
||||
template <class T>
|
||||
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<const cname *>(this)\n"); \
|
||||
fflush(stdout); \
|
||||
pybind11::function override \
|
||||
= pybind11::get_override(static_cast<const cname *>(this), name); \
|
||||
fflush(stderr); \
|
||||
printf("\nLOOOK AFTER static_cast<const cname *>(this)\n"); \
|
||||
fflush(stdout); \
|
||||
if (override) { \
|
||||
auto o = override(__VA_ARGS__); \
|
||||
PYBIND11_WARNING_PUSH \
|
||||
|
||||
@@ -28,7 +28,7 @@ struct SpBase {
|
||||
|
||||
std::shared_ptr<SpBase> pass_through_shd_ptr(const std::shared_ptr<SpBase> &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); }
|
||||
};
|
||||
|
||||
@@ -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<VirtBase> wp;
|
||||
};
|
||||
|
||||
std::shared_ptr<VirtBase> pass_through_sp_VirtBase(const std::shared_ptr<VirtBase> &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);
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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<VirtBase> sp;
|
||||
};
|
||||
|
||||
std::shared_ptr<VirtBase> pass_through_sp_VirtBase(const std::shared_ptr<VirtBase> &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);
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user