Skip to content

Commit 958a8eb

Browse files
committed
Fix Shutdown crash
1 parent ea3d47a commit 958a8eb

File tree

8 files changed

+43
-18
lines changed

8 files changed

+43
-18
lines changed

pythonnet/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ def unload():
6363
global _RUNTIME
6464
if _LOADER_ASSEMBLY is not None:
6565
func = _LOADER_ASSEMBLY["Python.Runtime.Loader.Shutdown"]
66-
if func(b"") != 0:
66+
if func(b"full_shutdown") != 0:
6767
raise RuntimeError("Failed to call Python.NET shutdown")
6868

6969
if _RUNTIME is not None:

src/runtime/classbase.cs

+2-3
Original file line numberDiff line numberDiff line change
@@ -356,17 +356,16 @@ public static void tp_dealloc(IntPtr ob)
356356
{
357357
Runtime.PyObject_ClearWeakRefs(ob);
358358
}
359-
tp_clear(ob);
359+
RemoveObjectDict(ob);
360+
Runtime.Py_CLEAR(ref self.tpHandle);
360361
Runtime.PyObject_GC_UnTrack(ob);
361362
Runtime.PyObject_GC_Del(ob);
362363
self.FreeGCHandle();
363364
}
364365

365366
public static int tp_clear(IntPtr ob)
366367
{
367-
ManagedType self = GetManagedObject(ob);
368368
ClearObjectDict(ob);
369-
Runtime.Py_CLEAR(ref self.tpHandle);
370369
return 0;
371370
}
372371

src/runtime/classmanager.cs

+2-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System.Runtime.InteropServices;
66
using System.Security;
77
using System.Linq;
8+
using System.Diagnostics;
89

910
namespace Python.Runtime
1011
{
@@ -270,7 +271,7 @@ private static void InitClassBase(Type type, ClassBase impl)
270271

271272
// Finally, initialize the class __dict__ and return the object.
272273
var dict = new BorrowedReference(Marshal.ReadIntPtr(tp, TypeOffset.tp_dict));
273-
274+
Debug.Assert(!dict.IsNull);
274275

275276
if (impl.dotNetMembers == null)
276277
{

src/runtime/extensiontype.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ void SetupGc ()
5555
/// </summary>
5656
public static void FinalizeObject(ManagedType self)
5757
{
58-
ClearObjectDict(self.pyHandle);
58+
RemoveObjectDict(self.pyHandle);
5959
Runtime.PyObject_GC_Del(self.pyHandle);
6060
// Not necessary for decref of `tpHandle`.
6161
self.FreeGCHandle();

src/runtime/managedtype.cs

+10
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,16 @@ protected virtual void OnSave(InterDomainContext context) { }
225225
protected virtual void OnLoad(InterDomainContext context) { }
226226

227227
protected static void ClearObjectDict(IntPtr ob)
228+
{
229+
IntPtr dict = GetObjectDict(ob);
230+
if (dict == IntPtr.Zero)
231+
{
232+
return;
233+
}
234+
Runtime.PyDict_Clear(dict);
235+
}
236+
237+
protected static void RemoveObjectDict(IntPtr ob)
228238
{
229239
IntPtr dict = GetObjectDict(ob);
230240
if (dict == IntPtr.Zero)

src/runtime/metatype.cs

+1-3
Original file line numberDiff line numberDiff line change
@@ -296,9 +296,7 @@ public static void tp_dealloc(IntPtr tp)
296296

297297
public static int tp_clear(IntPtr ob)
298298
{
299-
IntPtr type = Runtime.PyObject_TYPE(ob);
300-
int dictOffset = ObjectOffset.TypeDictOffset(type);
301-
Runtime.Py_SETREF(ob, dictOffset, IntPtr.Zero);
299+
ClearObjectDict(ob);
302300
return 0;
303301
}
304302

src/runtime/methodobject.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ public static IntPtr tp_repr(IntPtr ob)
217217
{
218218
var self = (MethodObject)GetManagedObject(ob);
219219
self.ClearMembers();
220-
ClearObjectDict(ob);
220+
RemoveObjectDict(ob);
221221
self.Dealloc();
222222
}
223223

src/runtime/runtime.cs

+25-8
Original file line numberDiff line numberDiff line change
@@ -503,15 +503,19 @@ private static void PyDictTryDelItem(BorrowedReference dict, string key)
503503
private static void MoveClrInstancesOnwershipToPython()
504504
{
505505
var objs = ManagedType.GetManagedObjects();
506-
var copyObjs = objs.ToArray();
507-
foreach (var entry in copyObjs)
506+
var copyObjs = new KeyValuePair<ManagedType, ManagedType.TrackTypes>[objs.Count];
508507
{
509-
ManagedType obj = entry.Key;
510-
if (!objs.ContainsKey(obj))
508+
int i = 0;
509+
foreach (var entry in objs)
511510
{
512-
System.Diagnostics.Debug.Assert(obj.gcHandle == default);
513-
continue;
511+
ManagedType obj = entry.Key;
512+
XIncref(obj.pyHandle);
513+
copyObjs[i++] = entry;
514514
}
515+
}
516+
foreach (var entry in copyObjs)
517+
{
518+
ManagedType obj = entry.Key;
515519
if (entry.Value == ManagedType.TrackTypes.Extension)
516520
{
517521
obj.CallTypeClear();
@@ -522,8 +526,21 @@ private static void MoveClrInstancesOnwershipToPython()
522526
PyObject_GC_Track(obj.pyHandle);
523527
}
524528
}
525-
obj.FreeGCHandle();
526-
Marshal.WriteIntPtr(obj.pyHandle, ObjectOffset.magic(obj.tpHandle), IntPtr.Zero);
529+
}
530+
foreach (var entry in copyObjs)
531+
{
532+
ManagedType obj = entry.Key;
533+
if (!objs.ContainsKey(obj))
534+
{
535+
System.Diagnostics.Debug.Assert(obj.gcHandle == default);
536+
continue;
537+
}
538+
if (obj.RefCount > 1)
539+
{
540+
obj.FreeGCHandle();
541+
Marshal.WriteIntPtr(obj.pyHandle, ObjectOffset.magic(obj.tpHandle), IntPtr.Zero);
542+
}
543+
XDecref(obj.pyHandle);
527544
}
528545
ManagedType.ClearTrackedObjects();
529546
}

0 commit comments

Comments
 (0)