Skip to content

Commit 50da522

Browse files
authored
clear weakref list when reflected object is destroyed (#1758)
this was missed when #1267 was superseded
1 parent 1cf616d commit 50da522

File tree

4 files changed

+30
-0
lines changed

4 files changed

+30
-0
lines changed

src/embed_tests/TestInstanceWrapping.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,16 @@ public void OverloadResolution_UnknownToObject()
3434
}
3535
}
3636

37+
[Test]
38+
public void WeakRefIsNone_AfterObjectIsGone()
39+
{
40+
using var makeref = Py.Import("weakref").GetAttr("ref");
41+
var ub = new UriBuilder().ToPython();
42+
using var weakref = makeref.Invoke(ub);
43+
ub.Dispose();
44+
Assert.IsTrue(weakref.Invoke().IsNone());
45+
}
46+
3747
class Base {}
3848
class Derived: Base { }
3949

src/runtime/Runtime.Delegates.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ static Delegates()
7878
PyObject_RichCompareBool = (delegate* unmanaged[Cdecl]<BorrowedReference, BorrowedReference, int, int>)GetFunctionByName(nameof(PyObject_RichCompareBool), GetUnmanagedDll(_PythonDll));
7979
PyObject_IsInstance = (delegate* unmanaged[Cdecl]<BorrowedReference, BorrowedReference, int>)GetFunctionByName(nameof(PyObject_IsInstance), GetUnmanagedDll(_PythonDll));
8080
PyObject_IsSubclass = (delegate* unmanaged[Cdecl]<BorrowedReference, BorrowedReference, int>)GetFunctionByName(nameof(PyObject_IsSubclass), GetUnmanagedDll(_PythonDll));
81+
PyObject_ClearWeakRefs = (delegate* unmanaged[Cdecl]<BorrowedReference, void>)GetFunctionByName(nameof(PyObject_ClearWeakRefs), GetUnmanagedDll(_PythonDll));
8182
PyCallable_Check = (delegate* unmanaged[Cdecl]<BorrowedReference, int>)GetFunctionByName(nameof(PyCallable_Check), GetUnmanagedDll(_PythonDll));
8283
PyObject_IsTrue = (delegate* unmanaged[Cdecl]<BorrowedReference, int>)GetFunctionByName(nameof(PyObject_IsTrue), GetUnmanagedDll(_PythonDll));
8384
PyObject_Not = (delegate* unmanaged[Cdecl]<BorrowedReference, int>)GetFunctionByName(nameof(PyObject_Not), GetUnmanagedDll(_PythonDll));
@@ -361,6 +362,7 @@ static Delegates()
361362
internal static delegate* unmanaged[Cdecl]<BorrowedReference, BorrowedReference, int, int> PyObject_RichCompareBool { get; }
362363
internal static delegate* unmanaged[Cdecl]<BorrowedReference, BorrowedReference, int> PyObject_IsInstance { get; }
363364
internal static delegate* unmanaged[Cdecl]<BorrowedReference, BorrowedReference, int> PyObject_IsSubclass { get; }
365+
internal static delegate* unmanaged[Cdecl]<BorrowedReference, void> PyObject_ClearWeakRefs { get; }
364366
internal static delegate* unmanaged[Cdecl]<BorrowedReference, int> PyCallable_Check { get; }
365367
internal static delegate* unmanaged[Cdecl]<BorrowedReference, int> PyObject_IsTrue { get; }
366368
internal static delegate* unmanaged[Cdecl]<BorrowedReference, int> PyObject_Not { get; }

src/runtime/Runtime.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -993,6 +993,18 @@ internal static int PyObject_Compare(BorrowedReference value1, BorrowedReference
993993

994994
internal static int PyObject_IsSubclass(BorrowedReference ob, BorrowedReference type) => Delegates.PyObject_IsSubclass(ob, type);
995995

996+
internal static void PyObject_ClearWeakRefs(BorrowedReference ob) => Delegates.PyObject_ClearWeakRefs(ob);
997+
998+
internal static BorrowedReference PyObject_GetWeakRefList(BorrowedReference ob)
999+
{
1000+
Debug.Assert(ob != null);
1001+
var type = PyObject_TYPE(ob);
1002+
int offset = Util.ReadInt32(type, TypeOffset.tp_weaklistoffset);
1003+
if (offset == 0) return BorrowedReference.Null;
1004+
Debug.Assert(offset > 0);
1005+
return Util.ReadRef(ob, offset);
1006+
}
1007+
9961008

9971009
internal static int PyCallable_Check(BorrowedReference o) => Delegates.PyCallable_Check(o);
9981010

src/runtime/Types/ClassBase.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,12 @@ public static void tp_dealloc(NewReference lastRef)
346346

347347
public static int tp_clear(BorrowedReference ob)
348348
{
349+
var weakrefs = Runtime.PyObject_GetWeakRefList(ob);
350+
if (weakrefs != null)
351+
{
352+
Runtime.PyObject_ClearWeakRefs(ob);
353+
}
354+
349355
if (TryFreeGCHandle(ob))
350356
{
351357
IntPtr addr = ob.DangerousGetAddress();

0 commit comments

Comments
 (0)