Skip to content

Commit

Permalink
test_keep_alive: Show that keep_alive cycle escapes GC
Browse files Browse the repository at this point in the history
  • Loading branch information
EricCousineau-TRI committed Dec 30, 2020
1 parent 8a9aec7 commit bd3e1a7
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 0 deletions.
1 change: 1 addition & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ set(PYBIND11_TEST_FILES
# test_tagbased_polymorphic.cpp
# test_union.cpp
# test_virtual_functions.cpp)
test_keep_alive.cpp
)
# cmake-format: on

Expand Down
12 changes: 12 additions & 0 deletions tests/test_keep_alive.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#include "pybind11_tests.h"

class SimpleClass {};

TEST_SUBMODULE(keep_alive, m) {
m.def("keep_alive_impl", [](py::handle nurse, py::handle patient) {
py::detail::keep_alive_impl(nurse, patient);
});

py::class_<SimpleClass>(m, "SimpleClass")
.def(py::init());
}
29 changes: 29 additions & 0 deletions tests/test_keep_alive.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# -*- coding: utf-8 -*-
# N.B. This is only focused on CPython, so using gc directly, rather than
# `pytest.gc_collect()`.
import gc
import weakref

from pybind11_tests import keep_alive as m


def test_keep_alive_cycle():
# See #2761.
o1 = m.SimpleClass()
wr1 = weakref.ref(o1)
o2 = m.SimpleClass()
wr2 = weakref.ref(o2)
assert wr1() is not None
assert wr2() is not None

# Add a direct cycle.
m.keep_alive_impl(o1, o2)
m.keep_alive_impl(o2, o1)

del o1
del o2
gc.collect()

# This shows that py::keep_alive will leak objects :(
assert wr1() is not None
assert wr2() is not None

0 comments on commit bd3e1a7

Please sign in to comment.