Join GitHub today
GitHub is home to over 50 million developers working together to host and review code, manage projects, and build software together.
Sign upGitHub is where the world builds software
Millions of developers and companies build, ship, and maintain their software on GitHub — the largest and most advanced development platform in the world.
Adds an unchecked version to get a BorrowedReference pointer #4
Conversation
And other code review changes
Even if netstandard lacks (for now) the necessary APIs for domain (un)loading, it is still possible to (un)load domains via the Mono C runtime.
In Runtime_data.cs
…e pointer" We Don't support python 2 anymore, but the CI machines may still be using it to build.
Codecov Report
@@ Coverage Diff @@
## soft-shutdown #4 +/- ##
==============================================
Coverage 86.25% 86.25%
==============================================
Files 1 1
Lines 291 291
==============================================
Hits 251 251
Misses 40 40
Flags with carried forward coverage won't be shown. Click here to find out more. Continue to review full report at Codecov.
|
| IntPtr capsule = PySys_GetObject("clr_data").DangerousGetAddressUnchecked(); | ||
| if (capsule != IntPtr.Zero) | ||
| { | ||
| IntPtr oldData = PyCapsule_GetPointer(capsule, null); | ||
| PyMem_Free(oldData); | ||
| PyCapsule_SetPointer(capsule, IntPtr.Zero); | ||
| } |
lostmsu
Sep 24, 2020
•
Now that you never own the pointer, you can use BorrowedReference and never call "Dangerous" methods on it. Make PyCapsule_GetPointer and PyCapsule_SetPointer take first argument as BorrowedReference.
Now that you never own the pointer, you can use BorrowedReference and never call "Dangerous" methods on it. Make PyCapsule_GetPointer and PyCapsule_SetPointer take first argument as BorrowedReference.
BadSingleton
Sep 24, 2020
Author
Make PyCapsule_GetPointer and PyCapsule_SetPointer take first argument as BorrowedReference
I don't think this is semantically correct. These methods can operate on something other than BorrowedReferences
Make PyCapsule_GetPointer and PyCapsule_SetPointer take first argument as BorrowedReference
I don't think this is semantically correct. These methods can operate on something other than BorrowedReferences
lostmsu
Sep 24, 2020
•
No, this is exactly right. The method borrows a capsule object in a similar way we use borrowed references. The second argument of course should stay as raw pointer.
Think of it this way: if you were to implement PyCapsule_GetPointer, you'd need a borrowed reference to the capsule in order to update it (as opposed to stealing or taking/giving up ownership).
No, this is exactly right. The method borrows a capsule object in a similar way we use borrowed references. The second argument of course should stay as raw pointer.
Think of it this way: if you were to implement PyCapsule_GetPointer, you'd need a borrowed reference to the capsule in order to update it (as opposed to stealing or taking/giving up ownership).
BadSingleton
Sep 25, 2020
Author
In this use case, it is. However in the case where I create the new capsule (and receive a NewReference), and then set the capsule's pointer with PyCapsule_SetPointer, well.. it's a bit weird. But as I said in another reply, NewReference in implicitly castable to borrowed reference, which makes it transparent to the user.
In this use case, it is. However in the case where I create the new capsule (and receive a NewReference), and then set the capsule's pointer with PyCapsule_SetPointer, well.. it's a bit weird. But as I said in another reply, NewReference in implicitly castable to borrowed reference, which makes it transparent to the user.
| @@ -96,7 +105,7 @@ internal static void RestoreRuntimeData() | |||
|
|
|||
| private static void RestoreRuntimeDataImpl() | |||
| { | |||
| IntPtr capsule = PySys_GetObject("clr_data").DangerousGetAddress(); | |||
| IntPtr capsule = PySys_GetObject("clr_data").DangerousGetAddressUnchecked(); | |||
lostmsu
Sep 24, 2020
•
Same here, you don't need the raw address.
Same here, you don't need the raw address.
BadSingleton
Sep 24, 2020
Author
I do need it. PyCapsule_GetPointer at line 113 needs an IntPtr. Sure I could add an overload for PyCapsule_GetPointer, but I think what we really need is an implicit operator.
I do need it. PyCapsule_GetPointer at line 113 needs an IntPtr. Sure I could add an overload for PyCapsule_GetPointer, but I think what we really need is an implicit operator.
| } | ||
| capsule = PyCapsule_New(mem, null, IntPtr.Zero); | ||
| ClearCLRData(); | ||
| IntPtr capsule = PyCapsule_New(mem, null, IntPtr.Zero); |
lostmsu
Sep 24, 2020
Ideally, this should have been NewReference, and decref below should be Dispose
Ideally, this should have been NewReference, and decref below should be Dispose
Also adds implicit IntPtr conversion operators to simplify their use.
| public static implicit operator IntPtr(in BorrowedReference self) => self.DangerousGetAddress(); | ||
|
|
lostmsu
Sep 24, 2020
This exposes dangerous shotgun as an innocent operator
This exposes dangerous shotgun as an innocent operator
| @@ -15,6 +15,10 @@ namespace Python.Runtime | |||
| public static implicit operator BorrowedReference(in NewReference reference) | |||
| => new BorrowedReference(reference.pointer); | |||
|
|
|||
| [Pure] | |||
| public static implicit operator IntPtr(in NewReference reference) | |||
lostmsu
Sep 24, 2020
Same
Same
| /// <remark> | ||
| /// We need this method because BorrowedReference can be implicitly casted to IntPtr. | ||
| /// </remark> | ||
| internal static void XDecref(BorrowedReference op) | ||
| { | ||
| throw new InvalidOperationException("Cannot DecRef a borrowed reference."); | ||
| } | ||
|
|
||
| /// <remark> | ||
| /// We need this method because NewReference can be implicitly casted to IntPtr. | ||
| /// </remark> | ||
| internal static void XDecref(NewReference op) | ||
| { | ||
| op.Dispose(); | ||
| } | ||
|
|
lostmsu
Sep 24, 2020
No implicit casts. The types were created specifically to avoid freely mixing different kinds of ownership for PyObject*.
No implicit casts. The types were created specifically to avoid freely mixing different kinds of ownership for PyObject*.
| @@ -2129,7 +2145,7 @@ internal static void Py_CLEAR(ref IntPtr ob) | |||
| //==================================================================== | |||
|
|
|||
| [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] | |||
| internal static extern IntPtr PyCapsule_New(IntPtr pointer, string name, IntPtr destructor); | |||
| internal static extern NewReference PyCapsule_New(IntPtr pointer, string name, IntPtr destructor); | |||
lostmsu
Sep 24, 2020
•
Re: implicit conversions to IntPtr: If you find it hard to change all the places, that use PyCapsule_New to use NewReference avoiding its dangerous methods as much as possible, just keep this return type IntPtr here, and use NewReference at the call site.
Re: implicit conversions to IntPtr: If you find it hard to change all the places, that use PyCapsule_New to use NewReference avoiding its dangerous methods as much as possible, just keep this return type IntPtr here, and use NewReference at the call site.
BadSingleton
Sep 24, 2020
Author
Not that I find it hard, I got confused by how the BorrowedReference gets marshalled. Or more like how it could get marshalled without needing an overload.
Also, NewReference is implicitly castable to BorrowedReference which solves most issues. The naming still bugs me a bit, but if it works, it works.
Not that I find it hard, I got confused by how the BorrowedReference gets marshalled. Or more like how it could get marshalled without needing an overload.
Also, NewReference is implicitly castable to BorrowedReference which solves most issues. The naming still bugs me a bit, but if it works, it works.
| @@ -2129,7 +2145,7 @@ internal static void Py_CLEAR(ref IntPtr ob) | |||
| //==================================================================== | |||
|
|
|||
| [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] | |||
| internal static extern IntPtr PyCapsule_New(IntPtr pointer, string name, IntPtr destructor); | |||
| internal static extern NewReference PyCapsule_New(IntPtr pointer, string name, IntPtr destructor); | |||
|
|
|||
| [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] | |||
| internal static extern IntPtr PyCapsule_GetPointer(IntPtr capsule, string name); | |||
lostmsu
Sep 24, 2020
This should be IntPtr PyCapsule_GetPointer(BorrowedReference capsule, string name)
This should be IntPtr PyCapsule_GetPointer(BorrowedReference capsule, string name)
lostmsu
Sep 24, 2020
Or you can add an overload.
Or you can add an overload.
|
travis-ci has one failure on an unrelated error:
|
|
Looks good to me. The new |
| /// <summary> | ||
| /// Gets a raw pointer to the Python object. Does not throw an exception | ||
| /// if the pointer is null | ||
| /// </summary> | ||
| public IntPtr DangerousGetAddressUnchecked() => this.pointer; |
lostmsu
Sep 25, 2020
NIT: I don't think you are actually using this anywhere
NIT: I don't think you are actually using this anywhere
BadSingleton
Sep 25, 2020
Author
Indeed, it's not used anymore
Indeed, it's not used anymore
And other code review changes.