From 0923f4f02c638468937b160495e7907b68ed402f Mon Sep 17 00:00:00 2001 From: Victor Milovanov Date: Fri, 4 Sep 2020 18:49:26 -0700 Subject: [PATCH 1/2] prevent crash during debugging when attempting to inspect PyObject without GIL --- src/runtime/Util.cs | 2 ++ src/runtime/debughelper.cs | 8 ++++++++ src/runtime/pyobject.cs | 5 +++++ src/runtime/runtime.cs | 11 ++++++++++- 4 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/runtime/Util.cs b/src/runtime/Util.cs index eb21cddbb..c70f5cf51 100644 --- a/src/runtime/Util.cs +++ b/src/runtime/Util.cs @@ -7,6 +7,8 @@ internal static class Util { internal const string UnstableApiMessage = "This API is unstable, and might be changed or removed in the next minor release"; + internal const string MinimalPythonVersionRequired = + "Only Python 3.5 or newer is supported"; internal static Int64 ReadCLong(IntPtr tp, int offset) { diff --git a/src/runtime/debughelper.cs b/src/runtime/debughelper.cs index 5e854bffd..25d32af5b 100644 --- a/src/runtime/debughelper.cs +++ b/src/runtime/debughelper.cs @@ -144,5 +144,13 @@ public static void AssertHasReferences(IntPtr obj) long refcount = Runtime.Refcount(obj); Debug.Assert(refcount > 0, "Object refcount is 0 or less"); } + + [Conditional("DEBUG")] + public static void EnsureGIL() + { + Debug.Assert(HaveInterpreterLock(), "GIL must be acquired"); + } + + public static bool HaveInterpreterLock() => Runtime.PyGILState_Check() == 1; } } diff --git a/src/runtime/pyobject.cs b/src/runtime/pyobject.cs index dea12ba1b..55e76019b 100644 --- a/src/runtime/pyobject.cs +++ b/src/runtime/pyobject.cs @@ -16,6 +16,7 @@ namespace Python.Runtime /// for details. /// [Serializable] + [DebuggerDisplay("{" + nameof(DebuggerDisplay) + ",nq}")] public partial class PyObject : DynamicObject, IEnumerable, IDisposable { #if TRACE_ALLOC @@ -1069,6 +1070,10 @@ public override string ToString() return result; } + string DebuggerDisplay => DebugUtil.HaveInterpreterLock() + ? this.ToString() + : $"pyobj at 0x{this.obj:X} (get Py.GIL to see more info)"; + /// /// Equals Method diff --git a/src/runtime/runtime.cs b/src/runtime/runtime.cs index 009412ea5..43ee08716 100644 --- a/src/runtime/runtime.cs +++ b/src/runtime/runtime.cs @@ -832,7 +832,7 @@ internal static unsafe long Refcount(IntPtr op) internal static IntPtr PyThreadState_Swap(IntPtr key) => Delegates.PyThreadState_Swap(key); - + internal static int PyGILState_Check() => Delegates.PyGILState_Check(); internal static IntPtr PyGILState_Ensure() => Delegates.PyGILState_Ensure(); @@ -2302,6 +2302,14 @@ static Delegates() PyThread_get_thread_ident = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyThread_get_thread_ident), GetUnmanagedDll(_PythonDll)); PyThread_set_key_value = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyThread_set_key_value), GetUnmanagedDll(_PythonDll)); PyThreadState_Swap = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyThreadState_Swap), GetUnmanagedDll(_PythonDll)); + try + { + PyGILState_Check = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyGILState_Check), GetUnmanagedDll(_PythonDll)); + } + catch (MissingMethodException e) + { + throw new NotSupportedException(Util.MinimalPythonVersionRequired, innerException: e); + } PyGILState_Ensure = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyGILState_Ensure), GetUnmanagedDll(_PythonDll)); PyGILState_Release = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyGILState_Release), GetUnmanagedDll(_PythonDll)); PyGILState_GetThisThreadState = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyGILState_GetThisThreadState), GetUnmanagedDll(_PythonDll)); @@ -2605,6 +2613,7 @@ static Delegates() internal static delegate* unmanaged[Cdecl] PyThread_get_thread_ident { get; } internal static delegate* unmanaged[Cdecl] PyThread_set_key_value { get; } internal static delegate* unmanaged[Cdecl] PyThreadState_Swap { get; } + internal static delegate* unmanaged[Cdecl] PyGILState_Check { get; } internal static delegate* unmanaged[Cdecl] PyGILState_Ensure { get; } internal static delegate* unmanaged[Cdecl] PyGILState_Release { get; } internal static delegate* unmanaged[Cdecl] PyGILState_GetThisThreadState { get; } From 00bc43dbf468f3297e72cd92560096af88392fc9 Mon Sep 17 00:00:00 2001 From: Victor Nova Date: Tue, 6 Jul 2021 18:52:40 -0700 Subject: [PATCH 2/2] added DebuggerDisplay to CLRObject --- src/runtime/clrobject.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/runtime/clrobject.cs b/src/runtime/clrobject.cs index 02f7baf65..07b816e05 100644 --- a/src/runtime/clrobject.cs +++ b/src/runtime/clrobject.cs @@ -5,6 +5,7 @@ namespace Python.Runtime { [Serializable] + [DebuggerDisplay("clrO: {inst}")] internal class CLRObject : ManagedType { internal object inst;