Skip to content

Commit 2b6b98e

Browse files
rfhaqueYannickJadoulBlistic
authored
Bugfix/Check actual value when deregistering pybind11 instance (#2252)
* Add tests demonstrating the problem with deregistering pybind11 instances * Fix deregistering of different pybind11 instance from internals Co-authored-by: Yannick Jadoul <[email protected]> Co-authored-by: Blistic <[email protected]>
1 parent b9d0027 commit 2b6b98e

File tree

3 files changed

+26
-1
lines changed

3 files changed

+26
-1
lines changed

include/pybind11/detail/class.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ inline bool deregister_instance_impl(void *ptr, instance *self) {
258258
auto &registered_instances = get_internals().registered_instances;
259259
auto range = registered_instances.equal_range(ptr);
260260
for (auto it = range.first; it != range.second; ++it) {
261-
if (Py_TYPE(self) == Py_TYPE(it->second)) {
261+
if (self == it->second) {
262262
registered_instances.erase(it);
263263
return true;
264264
}

tests/test_class.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,16 @@ TEST_SUBMODULE(class_, m) {
420420
py::class_<PyPrintDestructor>(m, "PyPrintDestructor")
421421
.def(py::init<>())
422422
.def("throw_something", &PyPrintDestructor::throw_something);
423+
424+
struct SamePointer {};
425+
static SamePointer samePointer;
426+
py::class_<SamePointer, std::unique_ptr<SamePointer, py::nodelete>>(m, "SamePointer")
427+
.def(py::init([]() { return &samePointer; }))
428+
.def("__del__", [](SamePointer&) { py::print("__del__ called"); });
429+
430+
struct Empty {};
431+
py::class_<Empty>(m, "Empty")
432+
.def(py::init<>());
423433
}
424434

425435
template <int N> class BreaksBase { public:

tests/test_class.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,3 +368,18 @@ class PyNonFinalFinalChild(m.IsNonFinalFinal):
368368
def test_exception_rvalue_abort():
369369
with pytest.raises(RuntimeError):
370370
m.PyPrintDestructor().throw_something()
371+
372+
373+
# https://github.com/pybind/pybind11/issues/1568
374+
def test_multiple_instances_with_same_pointer(capture):
375+
n = 100
376+
instances = [m.SamePointer() for _ in range(n)]
377+
for i in range(n):
378+
# We need to reuse the same allocated memory for with a different type,
379+
# to ensure the bug in `deregister_instance_impl` is detected. Otherwise
380+
# `Py_TYPE(self) == Py_TYPE(it->second)` will still succeed, even though
381+
# the `instance` is already deleted.
382+
instances[i] = m.Empty()
383+
# No assert: if this does not trigger the error
384+
# pybind11_fail("pybind11_object_dealloc(): Tried to deallocate unregistered instance!");
385+
# and just completes without crashing, we're good.

0 commit comments

Comments
 (0)