From 7fa3e8e3b5de6e77c9a0e5467952867df953cd37 Mon Sep 17 00:00:00 2001 From: Victor Nova Date: Sat, 9 Apr 2022 13:45:10 -0700 Subject: [PATCH] clear weak reference list when an extension type is destroyed According to official documentation for defining extension types, if they are to support weak references, they must clear weak reference list associated with the instance in tp_clear. Extension types were missed in https://github.com/pythonnet/pythonnet/pull/1758 ( 50da522c3b9098ebe10dde456efa81319083d6ba ) --- src/embed_tests/ExtensionTypes.cs | 32 ++++++++++++++++++++++++++++++ src/runtime/Types/ExtensionType.cs | 6 ++++++ src/runtime/Types/MetaType.cs | 6 ++++++ 3 files changed, 44 insertions(+) create mode 100644 src/embed_tests/ExtensionTypes.cs diff --git a/src/embed_tests/ExtensionTypes.cs b/src/embed_tests/ExtensionTypes.cs new file mode 100644 index 000000000..803845960 --- /dev/null +++ b/src/embed_tests/ExtensionTypes.cs @@ -0,0 +1,32 @@ +using System; + +using NUnit.Framework; + +using Python.Runtime; + +namespace Python.EmbeddingTest; + +public class ExtensionTypes +{ + [OneTimeSetUp] + public void SetUp() + { + PythonEngine.Initialize(); + } + + [OneTimeTearDown] + public void Dispose() + { + PythonEngine.Shutdown(); + } + + [Test] + public void WeakrefIsNone_AfterBoundMethodIsGone() + { + using var makeref = Py.Import("weakref").GetAttr("ref"); + var boundMethod = new UriBuilder().ToPython().GetAttr(nameof(UriBuilder.GetHashCode)); + var weakref = makeref.Invoke(boundMethod); + boundMethod.Dispose(); + Assert.IsTrue(weakref.Invoke().IsNone()); + } +} diff --git a/src/runtime/Types/ExtensionType.cs b/src/runtime/Types/ExtensionType.cs index d680067c2..439bd3314 100644 --- a/src/runtime/Types/ExtensionType.cs +++ b/src/runtime/Types/ExtensionType.cs @@ -86,6 +86,12 @@ public unsafe static void tp_dealloc(NewReference lastRef) public static int tp_clear(BorrowedReference ob) { + var weakrefs = Runtime.PyObject_GetWeakRefList(ob); + if (weakrefs != null) + { + Runtime.PyObject_ClearWeakRefs(ob); + } + if (TryFreeGCHandle(ob)) { bool deleted = loadedExtensions.Remove(ob.DangerousGetAddress()); diff --git a/src/runtime/Types/MetaType.cs b/src/runtime/Types/MetaType.cs index 7558269b4..1543711f6 100644 --- a/src/runtime/Types/MetaType.cs +++ b/src/runtime/Types/MetaType.cs @@ -273,6 +273,12 @@ public static NewReference mp_subscript(BorrowedReference tp, BorrowedReference /// public static void tp_dealloc(NewReference lastRef) { + var weakrefs = Runtime.PyObject_GetWeakRefList(lastRef.Borrow()); + if (weakrefs != null) + { + Runtime.PyObject_ClearWeakRefs(lastRef.Borrow()); + } + // Fix this when we dont cheat on the handle for subclasses! var flags = PyType.GetFlags(lastRef.Borrow());