diff --git a/src/runtime/classbase.cs b/src/runtime/classbase.cs index fed172e49..cf797ff30 100644 --- a/src/runtime/classbase.cs +++ b/src/runtime/classbase.cs @@ -373,7 +373,6 @@ public static int tp_clear(IntPtr ob) return baseClearResult; } } - if (self is not null) self.tpHandle = IntPtr.Zero; return 0; } diff --git a/src/runtime/managedtype.cs b/src/runtime/managedtype.cs index c22b479ac..d09088e79 100644 --- a/src/runtime/managedtype.cs +++ b/src/runtime/managedtype.cs @@ -28,8 +28,23 @@ internal enum TrackTypes internal IntPtr pyHandle; // PyObject * internal IntPtr tpHandle; // PyType * - internal BorrowedReference ObjectReference => new(pyHandle); - internal BorrowedReference TypeReference => new(tpHandle); + internal BorrowedReference ObjectReference + { + get + { + Debug.Assert(pyHandle != IntPtr.Zero); + return new(pyHandle); + } + } + + internal BorrowedReference TypeReference + { + get + { + Debug.Assert(tpHandle != IntPtr.Zero); + return new(tpHandle); + } + } private static readonly Dictionary _managedObjs = new Dictionary(); @@ -310,6 +325,8 @@ internal static void InitGCHandle(BorrowedReference reflectedClrObject, GCHandle internal static void SetGCHandle(BorrowedReference reflectedClrObject, BorrowedReference type, GCHandle newHandle) { + Debug.Assert(type != null); + Debug.Assert(reflectedClrObject != null); Debug.Assert(Runtime.PyObject_TypeCheck(reflectedClrObject, type)); int offset = Marshal.ReadInt32(type.DangerousGetAddress(), Offsets.tp_clr_inst_offset); diff --git a/src/runtime/runtime.cs b/src/runtime/runtime.cs index 015b6002e..acdf86c4e 100644 --- a/src/runtime/runtime.cs +++ b/src/runtime/runtime.cs @@ -2021,7 +2021,11 @@ internal static bool PyType_Check(IntPtr ob) internal static void PyType_Modified(BorrowedReference type) => Delegates.PyType_Modified(type); internal static bool PyType_IsSubtype(BorrowedReference t1, IntPtr ofType) => PyType_IsSubtype(t1, new BorrowedReference(ofType)); - internal static bool PyType_IsSubtype(BorrowedReference t1, BorrowedReference t2) => Delegates.PyType_IsSubtype(t1, t2); + internal static bool PyType_IsSubtype(BorrowedReference t1, BorrowedReference t2) + { + Debug.Assert(t1 != null && t2 != null); + return Delegates.PyType_IsSubtype(t1, t2); + } internal static bool PyObject_TypeCheck(IntPtr ob, IntPtr tp) => PyObject_TypeCheck(new BorrowedReference(ob), new BorrowedReference(tp)); diff --git a/tests/test_subclass.py b/tests/test_subclass.py index 4f3180480..fa82c3663 100644 --- a/tests/test_subclass.py +++ b/tests/test_subclass.py @@ -290,3 +290,19 @@ def __init__(self, i, s): assert len(calls) == 1 assert calls[0][0] == 1 assert calls[0][1] == "foo" + +# regression test for https://github.com/pythonnet/pythonnet/issues/1565 +def test_can_be_collected_by_gc(): + from Python.Test import BaseClass + + class Derived(BaseClass): + __namespace__ = 'test_can_be_collected_by_gc' + + inst = Derived() + cycle = [inst] + del inst + cycle.append(cycle) + del cycle + + import gc + gc.collect()