From c544eaad05626c2a9c459a0f79a7a51d7c4f8306 Mon Sep 17 00:00:00 2001 From: Victor Nova Date: Sat, 4 Sep 2021 18:14:01 -0700 Subject: [PATCH] call tp_clear (if any) of base unmanaged type when a reflected CLR object instance is cleared fixes https://github.com/pythonnet/pythonnet/issues/1476 : C# exceptions inherit from Python BaseException class, which has tp_clear. Prior to this change it was not called, leaving dangling references to BaseException.args and BaseException.__cause__.call tp_clear of base unmanaged type when a reflected CLR object instance is cleared fixes https://github.com/pythonnet/pythonnet/issues/1476 : C# exceptions inherit from Python BaseException class, which has tp_clear. Prior to this change it was not called, leaving dangling references to BaseException.args and BaseException.__cause__. --- src/embed_tests/Inheritance.cs | 14 ++++++++++++-- src/runtime/classbase.cs | 20 ++++++++++++++++++++ src/runtime/managedtype.cs | 10 ++++++++++ src/runtime/pytype.cs | 18 ++++++++++++++---- 4 files changed, 56 insertions(+), 6 deletions(-) diff --git a/src/embed_tests/Inheritance.cs b/src/embed_tests/Inheritance.cs index 50a461adb..58d66ed96 100644 --- a/src/embed_tests/Inheritance.cs +++ b/src/embed_tests/Inheritance.cs @@ -1,7 +1,5 @@ using System; using System.Collections.Generic; -using System.Diagnostics; -using System.Runtime.InteropServices; using NUnit.Framework; @@ -100,6 +98,18 @@ public void SetAdHocAttributes_WhenExtraBasePresent() int actual = scope.Eval($"{nameof(instance)}.{nameof(Inherited.XProp)}"); Assert.AreEqual(expected: Inherited.X, actual); } + + // https://github.com/pythonnet/pythonnet/issues/1476 + [Test] + public void BaseClearIsCalled() + { + using var scope = Py.CreateScope(); + scope.Set("exn", new Exception("42")); + var msg = scope.Eval("exn.args[0]"); + Assert.AreEqual(2, msg.Refcount); + scope.Set("exn", null); + Assert.AreEqual(1, msg.Refcount); + } } class ExtraBaseTypeProvider : IPythonBaseTypeProvider diff --git a/src/runtime/classbase.cs b/src/runtime/classbase.cs index 55f5c5b8f..fed172e49 100644 --- a/src/runtime/classbase.cs +++ b/src/runtime/classbase.cs @@ -1,6 +1,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Runtime.InteropServices; namespace Python.Runtime { @@ -365,11 +366,30 @@ public static int tp_clear(IntPtr ob) if (!isTypeObject) { ClearObjectDict(ob); + + int baseClearResult = BaseUnmanagedClear(ob); + if (baseClearResult != 0) + { + return baseClearResult; + } } if (self is not null) self.tpHandle = IntPtr.Zero; return 0; } + static unsafe int BaseUnmanagedClear(IntPtr ob) + { + var type = Runtime.PyObject_TYPE(new BorrowedReference(ob)); + var unmanagedBase = GetUnmanagedBaseType(type); + var clearPtr = Marshal.ReadIntPtr(unmanagedBase.DangerousGetAddress(), TypeOffset.tp_clear); + if (clearPtr == IntPtr.Zero) + { + return 0; + } + var clear = (delegate* unmanaged[Cdecl])clearPtr; + return clear(ob); + } + protected override void OnSave(InterDomainContext context) { base.OnSave(context); diff --git a/src/runtime/managedtype.cs b/src/runtime/managedtype.cs index e2f042bb8..c22b479ac 100644 --- a/src/runtime/managedtype.cs +++ b/src/runtime/managedtype.cs @@ -149,6 +149,16 @@ internal static bool IsManagedType(BorrowedReference type) return (flags & TypeFlags.HasClrInstance) != 0; } + internal static BorrowedReference GetUnmanagedBaseType(BorrowedReference managedType) + { + Debug.Assert(managedType != null && IsManagedType(managedType)); + do + { + managedType = PyType.GetBase(managedType); + } while (IsManagedType(managedType)); + return managedType; + } + public bool IsClrMetaTypeInstance() { Debug.Assert(Runtime.PyCLRMetaType != IntPtr.Zero); diff --git a/src/runtime/pytype.cs b/src/runtime/pytype.cs index afa957ecb..78cfad3f2 100644 --- a/src/runtime/pytype.cs +++ b/src/runtime/pytype.cs @@ -1,5 +1,6 @@ #nullable enable using System; +using System.Diagnostics; using System.Runtime.InteropServices; using Python.Runtime.Native; @@ -60,6 +61,11 @@ public static bool IsType(PyObject value) return Runtime.PyType_Check(value.obj); } + /// Checks if specified object is a Python type. + internal static bool IsType(BorrowedReference value) + { + return Runtime.PyType_Check(value.DangerousGetAddress()); + } /// /// Gets , which represents the specified CLR type. @@ -78,10 +84,7 @@ internal static PyType Get(Type clrType) internal BorrowedReference BaseReference { - get - { - return new(Marshal.ReadIntPtr(Handle, TypeOffset.tp_base)); - } + get => GetBase(Reference); set { var old = BaseReference.DangerousGetAddressOrNull(); @@ -100,6 +103,13 @@ internal IntPtr GetSlot(TypeSlotID slot) return Exceptions.ErrorCheckIfNull(result); } + internal static BorrowedReference GetBase(BorrowedReference type) + { + Debug.Assert(IsType(type)); + IntPtr basePtr = Marshal.ReadIntPtr(type.DangerousGetAddress(), TypeOffset.tp_base); + return new BorrowedReference(basePtr); + } + private static IntPtr EnsureIsType(in StolenReference reference) { IntPtr address = reference.DangerousGetAddressOrNull(); 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