mirror of
https://github.com/pybind/pybind11.git
synced 2025-02-18 06:30:54 +00:00
Adding test_multiple_registered_instances_for_same_pointee_leak. Subtle changes in smart_holder_type_caster_load, trying to work on weak_ptr for shared_ptr_trampoline_self_life_support, but that didn't work out. Manually fully leak-checked again.
This commit is contained in:
parent
595f7f4f6e
commit
a021e045a9
@ -18,6 +18,7 @@
|
|||||||
#include "type_caster_base.h"
|
#include "type_caster_base.h"
|
||||||
#include "typeid.h"
|
#include "typeid.h"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <new>
|
#include <new>
|
||||||
@ -343,6 +344,18 @@ struct smart_holder_type_caster_class_hooks : smart_holder_type_caster_base_tag
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct shared_ptr_trampoline_self_life_support {
|
||||||
|
PyObject *self;
|
||||||
|
explicit shared_ptr_trampoline_self_life_support(instance *inst)
|
||||||
|
: self{reinterpret_cast<PyObject *>(inst)} {
|
||||||
|
Py_INCREF(self);
|
||||||
|
}
|
||||||
|
void operator()(void *) {
|
||||||
|
gil_scoped_acquire gil;
|
||||||
|
Py_DECREF(self);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct smart_holder_type_caster_load {
|
struct smart_holder_type_caster_load {
|
||||||
using holder_type = pybindit::memory::smart_holder;
|
using holder_type = pybindit::memory::smart_holder;
|
||||||
@ -376,14 +389,6 @@ struct smart_holder_type_caster_load {
|
|||||||
return *raw_ptr;
|
return *raw_ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct shared_ptr_dec_ref_deleter {
|
|
||||||
PyObject *self;
|
|
||||||
void operator()(void *) {
|
|
||||||
gil_scoped_acquire gil;
|
|
||||||
Py_DECREF(self);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
std::shared_ptr<T> loaded_as_shared_ptr() const {
|
std::shared_ptr<T> loaded_as_shared_ptr() const {
|
||||||
if (load_impl.unowned_void_ptr_from_direct_conversion != nullptr)
|
if (load_impl.unowned_void_ptr_from_direct_conversion != nullptr)
|
||||||
throw cast_error("Unowned pointer from direct conversion cannot be converted to a"
|
throw cast_error("Unowned pointer from direct conversion cannot be converted to a"
|
||||||
@ -404,24 +409,26 @@ struct smart_holder_type_caster_load {
|
|||||||
std::shared_ptr<void> released_ptr = vptr_gd_ptr->released_ptr.lock();
|
std::shared_ptr<void> released_ptr = vptr_gd_ptr->released_ptr.lock();
|
||||||
if (released_ptr)
|
if (released_ptr)
|
||||||
return std::shared_ptr<T>(released_ptr, type_raw_ptr);
|
return std::shared_ptr<T>(released_ptr, type_raw_ptr);
|
||||||
auto self = reinterpret_cast<PyObject *>(load_impl.loaded_v_h.inst);
|
std::shared_ptr<T> to_be_released(
|
||||||
Py_INCREF(self);
|
type_raw_ptr,
|
||||||
std::shared_ptr<T> to_be_released(type_raw_ptr, shared_ptr_dec_ref_deleter{self});
|
shared_ptr_trampoline_self_life_support(load_impl.loaded_v_h.inst));
|
||||||
vptr_gd_ptr->released_ptr = to_be_released;
|
vptr_gd_ptr->released_ptr = to_be_released;
|
||||||
return to_be_released;
|
return to_be_released;
|
||||||
}
|
}
|
||||||
if (std::get_deleter<shared_ptr_dec_ref_deleter>(hld.vptr) != nullptr) {
|
auto sptsls_ptr = std::get_deleter<shared_ptr_trampoline_self_life_support>(hld.vptr);
|
||||||
|
if (sptsls_ptr != nullptr) {
|
||||||
// This code is reachable only if there are multiple registered_instances for the
|
// This code is reachable only if there are multiple registered_instances for the
|
||||||
// same pointee.
|
// same pointee.
|
||||||
// SMART_HOLDER_WIP: keep weak_ref
|
assert(reinterpret_cast<PyObject *>(load_impl.loaded_v_h.inst)
|
||||||
std::shared_ptr<void> void_shd_ptr = hld.template as_shared_ptr<void>();
|
!= sptsls_ptr->self);
|
||||||
return std::shared_ptr<T>(void_shd_ptr, type_raw_ptr);
|
return std::shared_ptr<T>(
|
||||||
|
type_raw_ptr,
|
||||||
|
shared_ptr_trampoline_self_life_support(load_impl.loaded_v_h.inst));
|
||||||
}
|
}
|
||||||
if (!pybindit::memory::type_has_shared_from_this(type_raw_ptr)) {
|
if (!pybindit::memory::type_has_shared_from_this(type_raw_ptr)) {
|
||||||
// SMART_HOLDER_WIP: keep weak_ref
|
return std::shared_ptr<T>(
|
||||||
auto self = reinterpret_cast<PyObject *>(load_impl.loaded_v_h.inst);
|
type_raw_ptr,
|
||||||
Py_INCREF(self);
|
shared_ptr_trampoline_self_life_support(load_impl.loaded_v_h.inst));
|
||||||
return std::shared_ptr<T>(type_raw_ptr, shared_ptr_dec_ref_deleter{self});
|
|
||||||
}
|
}
|
||||||
if (hld.vptr_is_external_shared_ptr) {
|
if (hld.vptr_is_external_shared_ptr) {
|
||||||
pybind11_fail("smart_holder_type_casters loaded_as_shared_ptr failure: not "
|
pybind11_fail("smart_holder_type_casters loaded_as_shared_ptr failure: not "
|
||||||
|
@ -170,6 +170,20 @@ def test_multiple_registered_instances_for_same_pointee():
|
|||||||
assert obj_pt.attachment_in_dict == "Obj0"
|
assert obj_pt.attachment_in_dict == "Obj0"
|
||||||
else:
|
else:
|
||||||
assert not hasattr(obj_pt, "attachment_in_dict")
|
assert not hasattr(obj_pt, "attachment_in_dict")
|
||||||
|
assert obj0.history == "PySft"
|
||||||
|
break # Comment out for manual leak checking (use `top` command).
|
||||||
|
|
||||||
|
|
||||||
|
def test_multiple_registered_instances_for_same_pointee_leak():
|
||||||
|
obj0 = PySft("")
|
||||||
|
while True:
|
||||||
|
stash1 = m.SftSharedPtrStash(1)
|
||||||
|
stash1.Add(m.Sft(obj0))
|
||||||
|
assert stash1.use_count(0) == 1
|
||||||
|
stash1.Add(m.Sft(obj0))
|
||||||
|
assert stash1.use_count(0) == 1
|
||||||
|
assert stash1.use_count(1) == 1
|
||||||
|
assert obj0.history == ""
|
||||||
break # Comment out for manual leak checking (use `top` command).
|
break # Comment out for manual leak checking (use `top` command).
|
||||||
|
|
||||||
|
|
||||||
|
@ -130,7 +130,7 @@ def test_infinite():
|
|||||||
tester = m.SpBaseTester()
|
tester = m.SpBaseTester()
|
||||||
while True:
|
while True:
|
||||||
tester.set_object(m.SpBase())
|
tester.set_object(m.SpBase())
|
||||||
return # Comment out for manual leak checking (use `top` command).
|
break # Comment out for manual leak checking (use `top` command).
|
||||||
|
|
||||||
|
|
||||||
def test_std_make_shared_factory():
|
def test_std_make_shared_factory():
|
||||||
@ -139,4 +139,6 @@ def test_std_make_shared_factory():
|
|||||||
super(PyChild, self).__init__(0)
|
super(PyChild, self).__init__(0)
|
||||||
|
|
||||||
obj = PyChild()
|
obj = PyChild()
|
||||||
assert m.pass_through_shd_ptr(obj) is obj
|
while True:
|
||||||
|
assert m.pass_through_shd_ptr(obj) is obj
|
||||||
|
break # Comment out for manual leak checking (use `top` command).
|
||||||
|
Loading…
Reference in New Issue
Block a user