8000 fixed Python derived types trying to double-free GCHandle when collec… · pythonnet/pythonnet@0325a8c · GitHub
[go: up one dir, main page]

Skip to content

Commit 0325a8c

Browse files
committed
fixed Python derived types trying to double-free GCHandle when collected by Python GC
1 parent a74ea86 commit 0325a8c

File tree

3 files changed

+26
-12
lines changed

3 files changed

+26
-12
lines changed

src/runtime/classderived.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,11 @@ internal ClassDerivedObject(Type tp) : base(tp)
8484
oldHandle.Free();
8585
}
8686

87+
/// <summary>
88+
/// No-op clear. Real cleanup happens in <seealso cref="Finalize(IntPtr)"/>
89+
/// </summary>
90+
public new static int tp_clear(BorrowedReference ob) => 0;
91+
8792
/// <summary>
8893
/// Called from Converter.ToPython for types that are python subclasses of managed types.
8994
/// The referenced python object is returned instead of a new wrapper.
@@ -854,6 +859,21 @@ public static void PyFinalize(IPythonDerivedType obj)
854859
Finalizer.Instance.AddDerivedFinalizedObject(ref self.RawObj, self.Run);
855860
}
856861

862+
internal static void Finalize(IntPtr derived)
863+
{
864+
bool deleted = CLRObject.reflectedObjects.Remove(derived);
865+
Debug.Assert(deleted);
866+
867+
var @ref = NewReference.DangerousFromPointer(derived);
868+
869+
ClassBase.tp_clear(@ref.Borrow());
870+
871+
// rare case when it's needed
872+
// matches correspdonging PyObject_GC_UnTrack
873+
// in ClassDerivedObject.tp_dealloc
874+
Runtime.PyObject_GC_Del(@ref.Steal());
875+
}
876+
857877
internal static FieldInfo? GetPyObjField(Type type) => type.GetField(PyObjName, PyObjFlags);
858878

859879
internal static UnsafeReferenceWithRun GetPyObj(IPythonDerivedType obj)

src/runtime/finalizer.cs

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -236,18 +236,11 @@ internal nint DisposeAll()
236236
continue;
237237
}
238238

239-
var @ref = NewReference.DangerousFromPointer(derived.PyObj);
240-
GCHandle gcHandle = ManagedType.GetGCHandle(@ref.Borrow());
241-
242-
bool deleted = CLRObject.reflectedObjects.Remove(derived.PyObj);
243-
Debug.Assert(deleted);
244-
// rare case when it's needed
245-
// matches correspdonging PyObject_GC_UnTrack
246-
// in ClassDerivedObject.tp_dealloc
247-
Runtime.PyObject_GC_Del(@ref.Steal());
248-
collected++;
239+
#pragma warning disable CS0618 // Type or member is obsolete. OK for internal use
240+
PythonDerivedType.Finalize(derived.PyObj);
241+
#pragma warning restore CS0618 // Type or member is obsolete
249242

250-
gcHandle.Free();
243+
collected++;
251244
}
252245
}
253246
finally

src/runtime/managedtype.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,8 @@ internal static bool TryFreeGCHandle(BorrowedReference reflectedClrObject, Borro
220220
IntPtr raw = Util.ReadIntPtr(reflectedClrObject, offset);
221221
if (raw == IntPtr.Zero) return false;
222222

223-
((GCHandle)raw).Free();
223+
var handle = (GCHandle)raw;
224+
handle.Free();
224225

225226
Util.WriteIntPtr(reflectedClrObject, offset, IntPtr.Zero);
226227
return true;

0 commit comments

Comments
 (0)
0