From 1f1f3588e038fb8056692ef9a672a26643517c27 Mon Sep 17 00:00:00 2001 From: Benoit Hudson Date: Fri, 24 Aug 2018 11:54:56 -0400 Subject: [PATCH 1/2] uni-56832: working crash solution on osx This should be platform-independent: - define tp_alloc, tp_clear, and tp_is_gc in native code - don't try the dlclose trick after shutdown This passes the pythonnet EmbeddingTest suite, plus the hotReloadCrashRepro test. Unknown if it passes the Python.Test suite: I can't figure out how to run those even in the unmodified pythonnet. --- src/runtime/runtime.cs | 17 ----------------- src/runtime/typemanager.cs | 35 ++++++++++++++++++++++++++++++++--- 2 files changed, 32 insertions(+), 20 deletions(-) diff --git a/src/runtime/runtime.cs b/src/runtime/runtime.cs index b29eb72ca..28cb30a47 100644 --- a/src/runtime/runtime.cs +++ b/src/runtime/runtime.cs @@ -476,23 +476,6 @@ internal static void Shutdown() Exceptions.Shutdown(); ImportHook.Shutdown(); Py_Finalize(); - - // Now unload the Python library from memory and load it again, providing a - // fresh interpreter. This prevents a crash (exception) on second domain reload - // https://stackoverflow.com/questions/2445536/unload-a-dll-loaded-using-dllimport - if (_PythonDll != "__Internal") - { - IntPtr dllLocal = NativeMethods.LoadLibrary(_PythonDll); - - // Twice: a first one for the call to LoadLibrary above, - // a second one for the original call to LoadLibrary (should result in unloading the Python library from memory) - NativeMethods.FreeLibrary(dllLocal); - NativeMethods.FreeLibrary(dllLocal); - - // Here the Python library is supposed to be unloaded. - // Load it again in order to get a fresh interpreter - NativeMethods.LoadLibrary(_PythonDll); - } } // called *without* the GIL acquired by clr._AtExit diff --git a/src/runtime/typemanager.cs b/src/runtime/typemanager.cs index 6570ee083..4d7196ad5 100644 --- a/src/runtime/typemanager.cs +++ b/src/runtime/typemanager.cs @@ -454,7 +454,7 @@ internal static IntPtr AllocateTypeObject(string name) /// internal static void InitializeSlots(IntPtr type, Type impl) { - var seen = new Hashtable(8); + var seen = new HashSet(); Type offsetType = typeof(TypeOffset); while (impl != null) @@ -473,7 +473,7 @@ internal static void InitializeSlots(IntPtr type, Type impl) continue; } - if (seen[name] != null) + if (seen.Contains(name)) { continue; } @@ -484,11 +484,40 @@ internal static void InitializeSlots(IntPtr type, Type impl) IntPtr slot = Interop.GetThunk(method); Marshal.WriteIntPtr(type, offset, slot); - seen[name] = 1; + seen.Add(name); } impl = impl.BaseType; } + + // Hack: for some objects (Classbase and ExtensionType) we need gc + // support. We need to provide three functions: + // - tp_traverse(object, ...) returns 0 + // - tp_clear(object) returns 0 + // - tp_is_gc(type) returns non-zero + // In addition, these functions can get called after a domain reload, + // so they must be implemented in native code. + // + // Py_GetVersion reliably returns non-zero and uses no arguments. + // + // PyAST_Check reads the object and returns zero unless it's a + // python AST node. You could violate this assumption by making a C# + // type that derives from ast.AST -- but it's not clear why you'd do that. + if (seen.Contains("tp_traverse")) + { + var lib = NativeMethods.LoadLibrary(Runtime.PythonDLL); + var zeroslot = NativeMethods.GetProcAddress(lib, "PyAST_Check"); + var trueslot = NativeMethods.GetProcAddress(lib, "Py_GetVersion"); + + var offset = (int)offsetType.GetField("tp_traverse").GetValue(offsetType); + Marshal.WriteIntPtr(type, offset, zeroslot); + + offset = (int)offsetType.GetField("tp_clear").GetValue(offsetType); + Marshal.WriteIntPtr(type, offset, zeroslot); + + offset = (int)offsetType.GetField("tp_is_gc").GetValue(offsetType); + Marshal.WriteIntPtr(type, offset, trueslot); + } } From 9c56428859a8897f93360d6d90779f5d8f3adb8b Mon Sep 17 00:00:00 2001 From: Benoit Hudson Date: Fri, 24 Aug 2018 12:01:57 -0400 Subject: [PATCH 2/2] uni-56832: fix Runtime.csproj so we can build on mono/osx. Added MONO_OSX define. Switched from UCS4 to UCS2. Removed a commented-out section that is required in VS for mac (but apparently OK to omit in VS for windows). --- src/runtime/Python.Runtime.csproj | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/runtime/Python.Runtime.csproj b/src/runtime/Python.Runtime.csproj index e2f7b0839..31e5c861b 100644 --- a/src/runtime/Python.Runtime.csproj +++ b/src/runtime/Python.Runtime.csproj @@ -1,8 +1,8 @@  - + Debug - AnyCPU + x86 {097B4AC0-74E9-4C58-BCF8-C69746EC8271} Library Python.Runtime @@ -22,35 +22,35 @@ - + - PYTHON2;PYTHON27;UCS4 + MONO_OSX;PYTHON2;PYTHON27;UCS2 true pdbonly - PYTHON2;PYTHON27;UCS2 + false - PYTHON3;PYTHON36;UCS4 + MONO_OSX;PYTHON3;PYTHON36;UCS4 true pdbonly false true - PYTHON2;PYTHON27;UCS4;TRACE;DEBUG + MONO_OSX;PYTHON2;PYTHON27;UCS2;TRACE;DEBUG false full false true - PYTHON3;PYTHON36;UCS4;TRACE;DEBUG + MONO_OSX;PYTHON3;PYTHON36;UCS4;TRACE;DEBUG false full false @@ -171,8 +171,14 @@ $(TargetPath) $(TargetDir)$(TargetName).pdb + + + + + + - \ No newline at end of file +