Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
BorrowedReference + example, that exposes dangerous pattern
  • Loading branch information
lostmsu committed Feb 13, 2020
commit 88944a2136e42e6cc4d38da3889d3c6ea2bffcd2
26 changes: 26 additions & 0 deletions src/runtime/BorrowedReference.cs
Original file line number Diff line number Diff line change
@@ -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;
}
}
4 changes: 2 additions & 2 deletions src/runtime/assemblymanager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -492,4 +492,4 @@ internal static Type[] GetTypes(Assembly a)
}
}
}
}
}
2 changes: 1 addition & 1 deletion src/runtime/methodbinder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This generates a compiler warning, that uncovers a potentially dangerous pattern, where kwargsDict may contain borrowed references.

}
Runtime.XDecref(keylist);
Runtime.XDecref(valueList);
Expand Down
6 changes: 4 additions & 2 deletions src/runtime/runtime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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());
/// <summary>
/// Function to access the internal PyUnicode/PyString object and
/// convert it to a managed string with the correct encoding.
Expand Down Expand Up @@ -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)
{
Expand Down