From 5e041afadbb119bd2816bd483adf62a347b9c639 Mon Sep 17 00:00:00 2001 From: Victor Nova Date: Fri, 4 Mar 2022 10:09:25 -0800 Subject: [PATCH 1/3] on runtime shutdown from Python release all slot holders, not only the ones, that belong to managed types --- src/runtime/TypeManager.cs | 16 ++++++++++------ src/runtime/Types/ModuleObject.cs | 1 - tests/test_engine.py | 4 ++++ 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/runtime/TypeManager.cs b/src/runtime/TypeManager.cs index 6057ca830..4b1e28fc2 100644 --- a/src/runtime/TypeManager.cs +++ b/src/runtime/TypeManager.cs @@ -51,18 +51,21 @@ internal static void Initialize() internal static void RemoveTypes() { - foreach (var type in cache.Values) + if (Runtime.HostedInPython) { - if (Runtime.HostedInPython - && _slotsHolders.TryGetValue(type, out var holder)) + foreach (var holder in _slotsHolders) { // If refcount > 1, it needs to reset the managed slot, // otherwise it can dealloc without any trick. - if (Runtime.Refcount(type) > 1) + if (holder.Key.Refcount > 1) { - holder.ResetSlots(); + holder.Value.ResetSlots(); } } + } + + foreach (var type in cache.Values) + { type.Dispose(); } cache.Clear(); @@ -507,7 +510,7 @@ internal static PyType CreateMetaType(Type impl, out SlotsHolder slotsHolder) { throw PythonException.ThrowLastAsClrException(); } - + BorrowedReference dict = Util.ReadRef(type, TypeOffset.tp_dict); using (var mod = Runtime.PyString_FromString("clr._internal")) Runtime.PyDict_SetItemString(dict, "__module__", mod.Borrow()); @@ -726,6 +729,7 @@ internal static void CopySlot(BorrowedReference from, BorrowedReference to, int internal static SlotsHolder CreateSlotsHolder(PyType type) { + type = new PyType(type); var holder = new SlotsHolder(type); _slotsHolders.Add(type, holder); return holder; diff --git a/src/runtime/Types/ModuleObject.cs b/src/runtime/Types/ModuleObject.cs index 1e86d4472..1cc9f04b2 100644 --- a/src/runtime/Types/ModuleObject.cs +++ b/src/runtime/Types/ModuleObject.cs @@ -542,7 +542,6 @@ public static Assembly AddReference(string name) /// The Type object [ModuleFunction] - [ForbidPythonThreads] public static Type GetClrType(Type type) { return type; diff --git a/tests/test_engine.py b/tests/test_engine.py index 60fdbf45d..06a44d561 100644 --- a/tests/test_engine.py +++ b/tests/test_engine.py @@ -41,3 +41,7 @@ def test_run_string(): assert sys.multiline_worked == 1 PythonEngine.ReleaseLock() + +def test_leak_type(): + import clr + sys._leaked_intptr = clr.GetClrType(System.IntPtr) From e9cbb87073e75500b3392ad057c06a132fb5ed3c Mon Sep 17 00:00:00 2001 From: Victor Nova Date: Thu, 7 Apr 2022 15:55:58 -0700 Subject: [PATCH 2/3] do not attempt to manually delete derived class instances after TypeManager is terminated and Python is shutting down --- pythonnet.sln | 1 + src/runtime/Runtime.cs | 9 ++++++--- src/runtime/TypeManager.cs | 1 + src/runtime/Types/ClassDerived.cs | 20 ++++++++++---------- 4 files changed, 18 insertions(+), 13 deletions(-) diff --git a/pythonnet.sln b/pythonnet.sln index 3b509518f..eb97cfbd0 100644 --- a/pythonnet.sln +++ b/pythonnet.sln @@ -25,6 +25,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Repo", "Repo", "{441A0123-F EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CI", "CI", "{D301657F-5EAF-4534-B280-B858D651B2E5}" ProjectSection(SolutionItems) = preProject + .github\workflows\ARM.yml = .github\workflows\ARM.yml .github\workflows\main.yml = .github\workflows\main.yml .github\workflows\nuget-preview.yml = .github\workflows\nuget-preview.yml EndProjectSection diff --git a/src/runtime/Runtime.cs b/src/runtime/Runtime.cs index e33c4624c..e358c0135 100644 --- a/src/runtime/Runtime.cs +++ b/src/runtime/Runtime.cs @@ -54,8 +54,9 @@ private static string GetDefaultDllName(Version version) } private static bool _isInitialized = false; - internal static bool IsInitialized => _isInitialized; + private static bool _typesInitialized = false; + internal static bool TypeManagerInitialized => _typesInitialized; internal static readonly bool Is32Bit = IntPtr.Size == 4; // .NET core: System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(OSPlatform.Windows) @@ -151,6 +152,7 @@ internal static void Initialize(bool initSigs = false) ClassManager.Reset(); ClassDerivedObject.Reset(); TypeManager.Initialize(); + _typesInitialized = true; // Initialize modules that depend on the runtime class. AssemblyManager.Initialize(); @@ -272,6 +274,7 @@ internal static void Shutdown() NullGCHandles(ExtensionType.loadedExtensions); ClassManager.RemoveClasses(); TypeManager.RemoveTypes(); + _typesInitialized = false; MetaType.Release(); PyCLRMetaType.Dispose(); @@ -291,9 +294,10 @@ internal static void Shutdown() Finalizer.Shutdown(); InternString.Shutdown(); + ResetPyMembers(); + if (!HostedInPython) { - ResetPyMembers(); GC.Collect(); GC.WaitForPendingFinalizers(); PyGILState_Release(state); @@ -310,7 +314,6 @@ internal static void Shutdown() } else { - ResetPyMembers(); PyGILState_Release(state); } } diff --git a/src/runtime/TypeManager.cs b/src/runtime/TypeManager.cs index 4b1e28fc2..84618df64 100644 --- a/src/runtime/TypeManager.cs +++ b/src/runtime/TypeManager.cs @@ -832,6 +832,7 @@ public void ResetSlots() var metatype = Runtime.PyObject_TYPE(Type); ManagedType.TryFreeGCHandle(Type, metatype); } + Runtime.PyType_Modified(Type); } public static IntPtr GetDefaultSlot(int offset) diff --git a/src/runtime/Types/ClassDerived.cs b/src/runtime/Types/ClassDerived.cs index da1bf0f9a..6c2c81b13 100644 --- a/src/runtime/Types/ClassDerived.cs +++ b/src/runtime/Types/ClassDerived.cs @@ -59,10 +59,7 @@ protected override NewReference NewObjectToPython(object obj, BorrowedReference // Decrement the python object's reference count. // This doesn't actually destroy the object, it just sets the reference to this object // to be a weak reference and it will be destroyed when the C# object is destroyed. - if (!self.IsNull()) - { - Runtime.XDecref(self.Steal()); - } + Runtime.XDecref(self.Steal()); return Converter.ToPython(obj, type.Value); } @@ -942,13 +939,16 @@ internal static void Finalize(IntPtr derived) var type = Runtime.PyObject_TYPE(@ref.Borrow()); - // rare case when it's needed - // matches correspdonging PyObject_GC_UnTrack - // in ClassDerivedObject.tp_dealloc - Runtime.PyObject_GC_Del(@ref.Steal()); + if (!Runtime.HostedInPython || Runtime.TypeManagerInitialized) + { + // rare case when it's needed + // matches correspdonging PyObject_GC_UnTrack + // in ClassDerivedObject.tp_dealloc + Runtime.PyObject_GC_Del(@ref.Steal()); - // must decref our type - Runtime.XDecref(StolenReference.DangerousFromPointer(type.DangerousGetAddress())); + // must decref our type + Runtime.XDecref(StolenReference.DangerousFromPointer(type.DangerousGetAddress())); + } } internal static FieldInfo? GetPyObjField(Type type) => type.GetField(PyObjName, PyObjFlags); From 58bd58c01c3ebe917c274d56737495a98eecb265 Mon Sep 17 00:00:00 2001 From: Victor Nova Date: Fri, 8 Apr 2022 08:42:03 -0700 Subject: [PATCH 3/3] Ensure that shutdown is called from Python --- pythonnet/__init__.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/pythonnet/__init__.py b/pythonnet/__init__.py index 7eec90f27..10dc403e4 100644 --- a/pythonnet/__init__.py +++ b/pythonnet/__init__.py @@ -16,7 +16,7 @@ def set_runtime(runtime): def set_default_runtime() -> None: - if sys.platform == 'win32': + if sys.platform == "win32": set_runtime(clr_loader.get_netfx()) else: set_runtime(clr_loader.get_mono()) @@ -36,14 +36,15 @@ def load(): set_default_runtime() dll_path = join(dirname(__file__), "runtime", "Python.Runtime.dll") - + _LOADER_ASSEMBLY = _RUNTIME.get_assembly(dll_path) func = _LOADER_ASSEMBLY["Python.Runtime.Loader.Initialize"] - if func(''.encode("utf8")) != 0: + if func(b"") != 0: raise RuntimeError("Failed to initialize Python.Runtime.dll") import atexit + atexit.register(unload) @@ -51,7 +52,7 @@ def unload(): global _RUNTIME if _LOADER_ASSEMBLY is not None: func = _LOADER_ASSEMBLY["Python.Runtime.Loader.Shutdown"] - if func(b"") != 0: + if func(b"full_shutdown") != 0: raise RuntimeError("Failed to call Python.NET shutdown") if _RUNTIME is not None: pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy