Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds an unchecked version to get a BorrowedReference pointer #4

Conversation

@BadSingleton
Copy link

@BadSingleton BadSingleton commented Sep 15, 2020

And other code review changes.

BadSingleton and others added 5 commits Sep 15, 2020
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.
Félix Bourbonnais
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-commenter
Copy link

@codecov-commenter codecov-commenter commented Sep 16, 2020

Codecov Report

Merging #4 into soft-shutdown will not change coverage.
The diff coverage is n/a.

Impacted file tree graph

@@              Coverage Diff               @@
##           soft-shutdown       #4   +/-   ##
==============================================
  Coverage          86.25%   86.25%           
==============================================
  Files                  1        1           
  Lines                291      291           
==============================================
  Hits                 251      251           
  Misses                40       40           
Flag Coverage Δ
#setup_linux 64.94% <ø> (ø)
#setup_windows 72.50% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.


Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 12c0206...ff956e4. Read the comment docs.

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);
}
Comment on lines 39 to 45

This comment has been minimized.

@lostmsu

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.

This comment has been minimized.

@BadSingleton

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

This comment has been minimized.

@lostmsu

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).

This comment has been minimized.

@BadSingleton

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.

@@ -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();

This comment has been minimized.

@lostmsu

lostmsu Sep 24, 2020

Same here, you don't need the raw address.

This comment has been minimized.

@BadSingleton

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.

}
capsule = PyCapsule_New(mem, null, IntPtr.Zero);
ClearCLRData();
IntPtr capsule = PyCapsule_New(mem, null, IntPtr.Zero);

This comment has been minimized.

@lostmsu

lostmsu Sep 24, 2020

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();

Comment on lines 13 to 14

This comment has been minimized.

@lostmsu

lostmsu Sep 24, 2020

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)

This comment has been minimized.

/// <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();
}

Comment on lines 751 to 766

This comment has been minimized.

@lostmsu

lostmsu Sep 24, 2020

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);

This comment has been minimized.

@lostmsu

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.

This comment has been minimized.

@BadSingleton

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.

@@ -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);

This comment has been minimized.

@lostmsu

lostmsu Sep 24, 2020

This should be IntPtr PyCapsule_GetPointer(BorrowedReference capsule, string name)

This comment has been minimized.

@lostmsu

lostmsu Sep 24, 2020

Or you can add an overload.

@BadSingleton
Copy link
Author

@BadSingleton BadSingleton commented Sep 25, 2020

travis-ci has one failure on an unrelated error:

CSC : error CS0009: Metadata file '/home/travis/.nuget/packages/microsoft.targetingpack.netframework.v4.5/1.0.1/lib/net45/System.Xml.dll' could not be opened -- Unexpected stream end. [/home/travis/build/amos402/pythonnet/src/testing/Python.Test.15.csproj]
Copy link

@lostmsu lostmsu left a comment

Looks good to me. The new Dangerous method is not used anywhere though, so should not be added.

/// <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;
Comment on lines 18 to 22

This comment has been minimized.

@lostmsu

lostmsu Sep 25, 2020

NIT: I don't think you are actually using this anywhere

This comment has been minimized.

@BadSingleton

BadSingleton Sep 25, 2020
Author

Indeed, it's not used anymore

@amos402 amos402 merged commit c7b134c into amos402:soft-shutdown Sep 29, 2020
4 checks passed
4 checks passed
codecov/patch Coverage not affected when comparing 12c0206...ff956e4
Details
codecov/project 86.25% (+0.00%) compared to 12c0206
Details
continuous-integration/appveyor/pr AppVeyor build succeeded
Details
continuous-integration/travis-ci/pr The Travis CI build passed
Details
@BadSingleton BadSingleton deleted the Unity-Technologies:soft-shutdown-review-comments-3 branch Oct 20, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked issues

Successfully merging this pull request may close these issues.

None yet

4 participants
You can’t perform that action at this time.