-
Notifications
You must be signed in to change notification settings - Fork 198
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
Reliability improvements for array marshalling #384
Reliability improvements for array marshalling #384
Conversation
Signed-off-by: Jeremy Koritzinsky <jekoritz@microsoft.com>
Signed-off-by: Jeremy Koritzinsky <jekoritz@microsoft.com>
@jkoritzinsky Can we get an example of the generated stub? |
From the By ref string array test: namespace DllImportGenerator.IntegrationTests
{
partial class NativeExportsNE
{
public partial class Arrays
{
public static partial void ReverseStrings(ref string[] strArray, out int numElements)
{
unsafe
{
ushort **__strArray_gen_native = default;
numElements = default;
try
{
//
// Marshal
//
{
string[] strArray_local = strArray;
__strArray_gen_native = null;
if (strArray != null)
{
int strArray__bytelen = checked(sizeof(ushort *) * strArray_local.Length);
__strArray_gen_native = (ushort **)System.Runtime.InteropServices.Marshal.AllocCoTaskMem(strArray__bytelen);
}
if (strArray_local != null)
for (int __i = 0; __i < strArray_local.Length; ++__i)
{
__strArray_gen_native[__i] = null;
if (strArray_local[__i] != null)
{
__strArray_gen_native[__i] = (ushort *)System.Runtime.InteropServices.Marshal.StringToCoTaskMemUni(strArray_local[__i]);
}
}
}
//
// Invoke
//
fixed (int *__numElements_gen_native = &numElements)
{
ReverseStrings__PInvoke__(&__strArray_gen_native, __numElements_gen_native);
}
//
// Unmarshal
//
{
string[] strArray_local;
if (__strArray_gen_native != null)
{
strArray_local = new string[checked((int)numElements)];
for (int __i = 0; __i < strArray_local.Length; ++__i)
{
strArray_local[__i] = __strArray_gen_native[__i] == null ? null : new string ((char *)__strArray_gen_native[__i]);
}
}
else
strArray_local = null;
strArray = strArray_local;
}
}
finally
{
//
// Cleanup
//
if (strArray != null)
for (int __i = 0; __i < strArray.Length; ++__i)
{
System.Runtime.InteropServices.Marshal.FreeCoTaskMem((System.IntPtr)__strArray_gen_native[__i]);
}
System.Runtime.InteropServices.Marshal.FreeCoTaskMem((System.IntPtr)__strArray_gen_native);
}
}
}
[System.Runtime.InteropServices.DllImportAttribute("NativeExportsNE", EntryPoint = "reverse_strings")]
extern private static unsafe void ReverseStrings__PInvoke__(ushort ***strArray, int *numElements);
}
}
} |
|
DllImportGenerator/DllImportGenerator/ArrayMarshallingCodeContext.cs
Outdated
Show resolved
Hide resolved
DllImportGenerator/DllImportGenerator/Marshalling/NonBlittableArrayMarshaller.cs
Outdated
Show resolved
Hide resolved
DllImportGenerator/DllImportGenerator/ArrayMarshallingCodeContext.cs
Outdated
Show resolved
Hide resolved
|
Why can't this be just |
Should this be |
|
Updated codegen: namespace DllImportGenerator.IntegrationTests
{
partial class NativeExportsNE
{
public partial class Arrays
{
public static partial void ReverseStrings(ref string[] strArray, out int numElements)
{
unsafe
{
ushort **__strArray_gen_native = default;
numElements = default;
//
// Setup
//
string[] strArray_local = strArray;
try
{
//
// Marshal
//
__strArray_gen_native = null;
if (strArray != null)
{
int strArray__bytelen = checked(sizeof(ushort *) * strArray_local.Length);
__strArray_gen_native = (ushort **)System.Runtime.InteropServices.Marshal.AllocCoTaskMem(strArray__bytelen);
}
if (strArray_local != null)
for (int __i = 0; __i < strArray_local.Length; ++__i)
{
__strArray_gen_native[__i] = null;
if (strArray_local[__i] != null)
{
__strArray_gen_native[__i] = (ushort *)System.Runtime.InteropServices.Marshal.StringToCoTaskMemUni(strArray_local[__i]);
}
}
//
// Invoke
//
fixed (int *__numElements_gen_native = &numElements)
{
ReverseStrings__PInvoke__(&__strArray_gen_native, __numElements_gen_native);
}
//
// Unmarshal
//
if (__strArray_gen_native != null)
{
strArray_local = new string[checked((int)numElements)];
for (int __i = 0; __i < strArray_local.Length; ++__i)
{
strArray_local[__i] = __strArray_gen_native[__i] == null ? null : new string ((char *)__strArray_gen_native[__i]);
}
}
else
strArray_local = null;
strArray = strArray_local;
}
finally
{
//
// Cleanup
//
if (strArray_local != null)
for (int __i = 0; __i < strArray_local.Length; ++__i)
{
System.Runtime.InteropServices.Marshal.FreeCoTaskMem((System.IntPtr)__strArray_gen_native[__i]);
}
System.Runtime.InteropServices.Marshal.FreeCoTaskMem((System.IntPtr)__strArray_gen_native);
}
}
}
[System.Runtime.InteropServices.DllImportAttribute("NativeExportsNE", EntryPoint = "reverse_strings")]
extern private static unsafe void ReverseStrings__PInvoke__(ushort ***strArray, int *numElements);
}
}
} |
I think all uses of |
I should be able to replace the rest of the usages of |
I think you still need to have up-front Clear with this structure. If there is an exception thrown by the The alternative that avoids up-front Clear would be to count how many slots got initialized and only free up those in the finally block. |
The up front clear is implemented in #379. If you want I can try porting it over to this PR, but I'd rather just get one of the PRs in, fix merge conflicts, and then get the other PR in. |
Does anyone have any more comments other than the up-front Clear? |
DllImportGenerator/DllImportGenerator/Marshalling/NonBlittableArrayMarshaller.cs
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. My only other ask would be to add any relevant details to our design docs.
Guard against byte length overflow. Use a local when marshalling by-ref arrays to avoid multithreading issues.