From 4a84a1e35f072fe506e1f9d0d85b45ecdf0bbcdf Mon Sep 17 00:00:00 2001 From: Victor Milovanov Date: Thu, 13 Feb 2020 14:42:46 -0800 Subject: [PATCH 1/9] NewReference type and an example usage --- src/runtime/NewReference.cs | 26 ++++++++++++++++++++++++++ src/runtime/NonCopyableAttribute.cs | 6 ++++++ src/runtime/Python.Runtime.15.csproj | 9 ++++++++- src/runtime/pydict.cs | 7 ++++--- src/runtime/runtime.cs | 2 +- 5 files changed, 45 insertions(+), 5 deletions(-) create mode 100644 src/runtime/NewReference.cs create mode 100644 src/runtime/NonCopyableAttribute.cs diff --git a/src/runtime/NewReference.cs b/src/runtime/NewReference.cs new file mode 100644 index 000000000..d9f6f8a37 --- /dev/null +++ b/src/runtime/NewReference.cs @@ -0,0 +1,26 @@ +namespace Python.Runtime +{ + using System; + [NonCopyable] + ref struct NewReference + { + public IntPtr Pointer { get; set; } + public bool IsNull => this.Pointer == IntPtr.Zero; + + public PyObject ToPyObject() + { + if (this.IsNull) throw new NullReferenceException(); + + var result = new PyObject(this.Pointer); + this.Pointer = IntPtr.Zero; + return result; + } + + public void Dispose() + { + if (!this.IsNull) + Runtime.XDecref(this.Pointer); + this.Pointer = IntPtr.Zero; + } + } +} diff --git a/src/runtime/NonCopyableAttribute.cs b/src/runtime/NonCopyableAttribute.cs new file mode 100644 index 000000000..63d36ab42 --- /dev/null +++ b/src/runtime/NonCopyableAttribute.cs @@ -0,0 +1,6 @@ +namespace Python.Runtime +{ + using System; + [AttributeUsage(AttributeTargets.Struct)] + class NonCopyableAttribute : Attribute { } +} diff --git a/src/runtime/Python.Runtime.15.csproj b/src/runtime/Python.Runtime.15.csproj index c31d4bf91..b4570499b 100644 --- a/src/runtime/Python.Runtime.15.csproj +++ b/src/runtime/Python.Runtime.15.csproj @@ -30,7 +30,7 @@ ..\..\ $(SolutionDir)\bin\ $(PythonBuildDir)\$(TargetFramework)\ - 7.3 + 8.0 True ..\pythonnet.snk $(PYTHONNET_DEFINE_CONSTANTS) @@ -129,6 +129,13 @@ + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + diff --git a/src/runtime/pydict.cs b/src/runtime/pydict.cs index 7237d1990..53582ad26 100644 --- a/src/runtime/pydict.cs +++ b/src/runtime/pydict.cs @@ -139,12 +139,13 @@ public PyObject Values() /// public PyObject Items() { - IntPtr items = Runtime.PyDict_Items(obj); - if (items == IntPtr.Zero) + using var items = Runtime.PyDict_Items(this.obj); + if (items.IsNull) { throw new PythonException(); } - return new PyObject(items); + + return items.ToPyObject(); } diff --git a/src/runtime/runtime.cs b/src/runtime/runtime.cs index 7748bafa9..d550fd83f 100644 --- a/src/runtime/runtime.cs +++ b/src/runtime/runtime.cs @@ -1591,7 +1591,7 @@ internal static bool PyDict_Check(IntPtr ob) internal static extern IntPtr PyDict_Values(IntPtr pointer); [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyDict_Items(IntPtr pointer); + internal static extern NewReference PyDict_Items(IntPtr pointer); [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] internal static extern IntPtr PyDict_Copy(IntPtr pointer); From 88944a2136e42e6cc4d38da3889d3c6ea2bffcd2 Mon Sep 17 00:00:00 2001 From: Victor Milovanov Date: Thu, 13 Feb 2020 15:12:30 -0800 Subject: [PATCH 2/9] BorrowedReference + example, that exposes dangerous pattern --- src/runtime/BorrowedReference.cs | 26 ++++++++++++++++++++++++++ src/runtime/assemblymanager.cs | 4 ++-- src/runtime/methodbinder.cs | 2 +- src/runtime/runtime.cs | 6 ++++-- 4 files changed, 33 insertions(+), 5 deletions(-) create mode 100644 src/runtime/BorrowedReference.cs diff --git a/src/runtime/BorrowedReference.cs b/src/runtime/BorrowedReference.cs new file mode 100644 index 000000000..17f0960fe --- /dev/null +++ b/src/runtime/BorrowedReference.cs @@ -0,0 +1,26 @@ +namespace Python.Runtime +{ + using System; + [NonCopyable] + ref struct BorrowedReference + { + public IntPtr Pointer; + public bool IsNull => this.Pointer == IntPtr.Zero; + + public PyObject ToPyObject() + { + if (this.IsNull) throw new NullReferenceException(); + + Runtime.XIncref(this.Pointer); + return new PyObject(this.Pointer); + } + } + + static class BorrowedReferenceExtensions { + [Obsolete("Use overloads, that take BorrowedReference or NewReference")] + public static IntPtr DangerousGetAddress(this in BorrowedReference reference) + => reference.IsNull() ? throw new NullReferenceException() : reference.Pointer; + public static bool IsNull(this in BorrowedReference reference) + => reference.Pointer == IntPtr.Zero; + } +} diff --git a/src/runtime/assemblymanager.cs b/src/runtime/assemblymanager.cs index 3085bb639..9d0296d47 100644 --- a/src/runtime/assemblymanager.cs +++ b/src/runtime/assemblymanager.cs @@ -145,7 +145,7 @@ internal static void UpdatePath() probed.Clear(); for (var i = 0; i < count; i++) { - IntPtr item = Runtime.PyList_GetItem(list, i); + BorrowedReference item = Runtime.PyList_GetItem(list, i); string path = Runtime.GetManagedString(item); if (path != null) { @@ -492,4 +492,4 @@ internal static Type[] GetTypes(Assembly a) } } } -} \ No newline at end of file +} diff --git a/src/runtime/methodbinder.cs b/src/runtime/methodbinder.cs index 8a7fc1930..4e8698da1 100644 --- a/src/runtime/methodbinder.cs +++ b/src/runtime/methodbinder.cs @@ -292,7 +292,7 @@ internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw, MethodBase info, Meth for (int i = 0; i < pynkwargs; ++i) { var keyStr = Runtime.GetManagedString(Runtime.PyList_GetItem(keylist, i)); - kwargDict[keyStr] = Runtime.PyList_GetItem(valueList, i); + kwargDict[keyStr] = Runtime.PyList_GetItem(valueList, i).DangerousGetAddress(); } Runtime.XDecref(keylist); Runtime.XDecref(valueList); diff --git a/src/runtime/runtime.cs b/src/runtime/runtime.cs index d550fd83f..4cceea42d 100644 --- a/src/runtime/runtime.cs +++ b/src/runtime/runtime.cs @@ -1509,6 +1509,8 @@ internal static IntPtr PyUnicode_FromString(string s) return PyUnicode_FromUnicode(s, s.Length); } + internal static string GetManagedString(in BorrowedReference borrowedReference) + => GetManagedString(borrowedReference.DangerousGetAddress()); /// /// Function to access the internal PyUnicode/PyString object and /// convert it to a managed string with the correct encoding. @@ -1631,13 +1633,13 @@ internal static IntPtr PyList_New(long size) [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] internal static extern IntPtr PyList_AsTuple(IntPtr pointer); - internal static IntPtr PyList_GetItem(IntPtr pointer, long index) + internal static BorrowedReference PyList_GetItem(IntPtr pointer, long index) { return PyList_GetItem(pointer, new IntPtr(index)); } [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - private static extern IntPtr PyList_GetItem(IntPtr pointer, IntPtr index); + private static extern BorrowedReference PyList_GetItem(IntPtr pointer, IntPtr index); internal static int PyList_SetItem(IntPtr pointer, long index, IntPtr value) { From e1ba92c4eb0b9194e825799f4596add5d63077e0 Mon Sep 17 00:00:00 2001 From: Victor Milovanov Date: Thu, 13 Feb 2020 15:25:03 -0800 Subject: [PATCH 3/9] actually, borrowed refrences can be copied --- src/runtime/BorrowedReference.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/runtime/BorrowedReference.cs b/src/runtime/BorrowedReference.cs index 17f0960fe..5c2a9fc2c 100644 --- a/src/runtime/BorrowedReference.cs +++ b/src/runtime/BorrowedReference.cs @@ -1,7 +1,6 @@ namespace Python.Runtime { using System; - [NonCopyable] ref struct BorrowedReference { public IntPtr Pointer; From 2d11f829c3fcbfafd043ce3f1ca1518445f4ff9b Mon Sep 17 00:00:00 2001 From: Victor Milovanov Date: Thu, 13 Feb 2020 15:37:15 -0800 Subject: [PATCH 4/9] make BorrowedReference readonly ref struct --- src/runtime/BorrowedReference.cs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/runtime/BorrowedReference.cs b/src/runtime/BorrowedReference.cs index 5c2a9fc2c..00644ebe5 100644 --- a/src/runtime/BorrowedReference.cs +++ b/src/runtime/BorrowedReference.cs @@ -1,9 +1,9 @@ namespace Python.Runtime { using System; - ref struct BorrowedReference + readonly ref struct BorrowedReference { - public IntPtr Pointer; + public readonly IntPtr Pointer; public bool IsNull => this.Pointer == IntPtr.Zero; public PyObject ToPyObject() @@ -13,13 +13,14 @@ public PyObject ToPyObject() Runtime.XIncref(this.Pointer); return new PyObject(this.Pointer); } - } - static class BorrowedReferenceExtensions { [Obsolete("Use overloads, that take BorrowedReference or NewReference")] - public static IntPtr DangerousGetAddress(this in BorrowedReference reference) - => reference.IsNull() ? throw new NullReferenceException() : reference.Pointer; - public static bool IsNull(this in BorrowedReference reference) - => reference.Pointer == IntPtr.Zero; + public IntPtr DangerousGetAddress() + => this.IsNull ? throw new NullReferenceException() : this.Pointer; + + BorrowedReference(IntPtr pointer) + { + this.Pointer = pointer; + } } } From dbb3dc539884146038c7567f2071480abf00b54a Mon Sep 17 00:00:00 2001 From: Victor Milovanov Date: Thu, 13 Feb 2020 15:43:13 -0800 Subject: [PATCH 5/9] updated old project file --- src/runtime/Python.Runtime.csproj | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/runtime/Python.Runtime.csproj b/src/runtime/Python.Runtime.csproj index 0c2f912de..8cf39d6ff 100644 --- a/src/runtime/Python.Runtime.csproj +++ b/src/runtime/Python.Runtime.csproj @@ -15,7 +15,7 @@ ..\..\ $(SolutionDir)\bin\ Properties - 7.3 + 8.0 true false ..\pythonnet.snk @@ -83,6 +83,7 @@ + @@ -119,6 +120,8 @@ + + From 7304b25cf336264c8c078110d5418fbc2598a475 Mon Sep 17 00:00:00 2001 From: Victor Milovanov Date: Thu, 13 Feb 2020 15:51:18 -0800 Subject: [PATCH 6/9] BorrowedReference.Pointer is a private readonly field --- src/runtime/BorrowedReference.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/runtime/BorrowedReference.cs b/src/runtime/BorrowedReference.cs index 00644ebe5..9b533e9d0 100644 --- a/src/runtime/BorrowedReference.cs +++ b/src/runtime/BorrowedReference.cs @@ -3,24 +3,24 @@ namespace Python.Runtime using System; readonly ref struct BorrowedReference { - public readonly IntPtr Pointer; - public bool IsNull => this.Pointer == IntPtr.Zero; + readonly IntPtr pointer; + public bool IsNull => this.pointer == IntPtr.Zero; public PyObject ToPyObject() { if (this.IsNull) throw new NullReferenceException(); - Runtime.XIncref(this.Pointer); - return new PyObject(this.Pointer); + Runtime.XIncref(this.pointer); + return new PyObject(this.pointer); } [Obsolete("Use overloads, that take BorrowedReference or NewReference")] public IntPtr DangerousGetAddress() - => this.IsNull ? throw new NullReferenceException() : this.Pointer; + => this.IsNull ? throw new NullReferenceException() : this.pointer; BorrowedReference(IntPtr pointer) { - this.Pointer = pointer; + this.pointer = pointer; } } } From 2bc218c23e2093b068c747c0a9e9890f441b4127 Mon Sep 17 00:00:00 2001 From: Victor Milovanov Date: Thu, 13 Feb 2020 15:58:35 -0800 Subject: [PATCH 7/9] drop C# 8.0 requirement --- src/runtime/Python.Runtime.15.csproj | 2 +- src/runtime/Python.Runtime.csproj | 2 +- src/runtime/pydict.cs | 17 ++++++++++++----- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/runtime/Python.Runtime.15.csproj b/src/runtime/Python.Runtime.15.csproj index b4570499b..fd4f3416a 100644 --- a/src/runtime/Python.Runtime.15.csproj +++ b/src/runtime/Python.Runtime.15.csproj @@ -30,7 +30,7 @@ ..\..\ $(SolutionDir)\bin\ $(PythonBuildDir)\$(TargetFramework)\ - 8.0 + 7.3 True ..\pythonnet.snk $(PYTHONNET_DEFINE_CONSTANTS) diff --git a/src/runtime/Python.Runtime.csproj b/src/runtime/Python.Runtime.csproj index 8cf39d6ff..c79afee3e 100644 --- a/src/runtime/Python.Runtime.csproj +++ b/src/runtime/Python.Runtime.csproj @@ -15,7 +15,7 @@ ..\..\ $(SolutionDir)\bin\ Properties - 8.0 + 7.3 true false ..\pythonnet.snk diff --git a/src/runtime/pydict.cs b/src/runtime/pydict.cs index 53582ad26..6d61cff76 100644 --- a/src/runtime/pydict.cs +++ b/src/runtime/pydict.cs @@ -139,13 +139,20 @@ public PyObject Values() /// public PyObject Items() { - using var items = Runtime.PyDict_Items(this.obj); - if (items.IsNull) + var items = Runtime.PyDict_Items(this.obj); + try { - throw new PythonException(); - } + if (items.IsNull) + { + throw new PythonException(); + } - return items.ToPyObject(); + return items.ToPyObject(); + } + finally + { + items.Dispose(); + } } From 2cf9fc36872789bbbb863a173addb4b35b7c5e95 Mon Sep 17 00:00:00 2001 From: Victor Milovanov Date: Sun, 23 Feb 2020 11:12:58 -0800 Subject: [PATCH 8/9] renamed NewReference.ToPyObject to MoveToPyObject removed public property Pointer from NewReference and replaced with DangerousGetAddress --- src/runtime/NewReference.cs | 18 +++++++++++------- src/runtime/pydict.cs | 2 +- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/runtime/NewReference.cs b/src/runtime/NewReference.cs index d9f6f8a37..f66b3bca3 100644 --- a/src/runtime/NewReference.cs +++ b/src/runtime/NewReference.cs @@ -4,23 +4,27 @@ namespace Python.Runtime [NonCopyable] ref struct NewReference { - public IntPtr Pointer { get; set; } - public bool IsNull => this.Pointer == IntPtr.Zero; + IntPtr pointer; + public bool IsNull => this.pointer == IntPtr.Zero; - public PyObject ToPyObject() + /// Gets a raw pointer to the Python object + public IntPtr DangerousGetAddress() + => this.IsNull ? throw new NullReferenceException() : this.pointer; + + public PyObject MoveToPyObject() { if (this.IsNull) throw new NullReferenceException(); - var result = new PyObject(this.Pointer); - this.Pointer = IntPtr.Zero; + var result = new PyObject(this.pointer); + this.pointer = IntPtr.Zero; return result; } public void Dispose() { if (!this.IsNull) - Runtime.XDecref(this.Pointer); - this.Pointer = IntPtr.Zero; + Runtime.XDecref(this.pointer); + this.pointer = IntPtr.Zero; } } } diff --git a/src/runtime/pydict.cs b/src/runtime/pydict.cs index 6d61cff76..b396f4f3d 100644 --- a/src/runtime/pydict.cs +++ b/src/runtime/pydict.cs @@ -147,7 +147,7 @@ public PyObject Items() throw new PythonException(); } - return items.ToPyObject(); + return items.MoveToPyObject(); } finally { From 6ae63cd9678cd42545cd30b9be336b8ec5240045 Mon Sep 17 00:00:00 2001 From: Victor Milovanov Date: Sun, 23 Feb 2020 11:13:24 -0800 Subject: [PATCH 9/9] added xmldoc comments to *Reference members --- src/runtime/BorrowedReference.cs | 14 +++++--------- src/runtime/NewReference.cs | 11 ++++++++++- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/runtime/BorrowedReference.cs b/src/runtime/BorrowedReference.cs index 9b533e9d0..7dbc7a811 100644 --- a/src/runtime/BorrowedReference.cs +++ b/src/runtime/BorrowedReference.cs @@ -1,20 +1,16 @@ namespace Python.Runtime { using System; + /// + /// Represents a reference to a Python object, that is being lent, and + /// can only be safely used until execution returns to the caller. + /// readonly ref struct BorrowedReference { readonly IntPtr pointer; public bool IsNull => this.pointer == IntPtr.Zero; - public PyObject ToPyObject() - { - if (this.IsNull) throw new NullReferenceException(); - - Runtime.XIncref(this.pointer); - return new PyObject(this.pointer); - } - - [Obsolete("Use overloads, that take BorrowedReference or NewReference")] + /// Gets a raw pointer to the Python object public IntPtr DangerousGetAddress() => this.IsNull ? throw new NullReferenceException() : this.pointer; diff --git a/src/runtime/NewReference.cs b/src/runtime/NewReference.cs index f66b3bca3..3b45f821f 100644 --- a/src/runtime/NewReference.cs +++ b/src/runtime/NewReference.cs @@ -1,6 +1,9 @@ namespace Python.Runtime { using System; + /// + /// Represents a reference to a Python object, that is tracked by Python's reference counting. + /// [NonCopyable] ref struct NewReference { @@ -11,6 +14,10 @@ ref struct NewReference public IntPtr DangerousGetAddress() => this.IsNull ? throw new NullReferenceException() : this.pointer; + /// + /// Returns wrapper around this reference, which now owns + /// the pointer. Sets the original reference to null, as it no longer owns it. + /// public PyObject MoveToPyObject() { if (this.IsNull) throw new NullReferenceException(); @@ -19,7 +26,9 @@ public PyObject MoveToPyObject() this.pointer = IntPtr.Zero; return result; } - + /// + /// Removes this reference to a Python object, and sets it to null. + /// public void Dispose() { if (!this.IsNull) 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