Skip to content

Commit

Permalink
Fix AVE in PtrToString on .NET 8 & remove unnecessary marshalling (do…
Browse files Browse the repository at this point in the history
…tnet#1990)

* Fix AVE in PtrToString on .NET 8 & remove unnecessary marshalling

* Review comments
  • Loading branch information
Perksey committed Mar 20, 2024
1 parent 4f76a9f commit f98e5e5
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 14 deletions.
52 changes: 43 additions & 9 deletions src/Core/Silk.NET.Core/Native/SilkMarshal.cs
Original file line number Diff line number Diff line change
Expand Up @@ -512,19 +512,53 @@ public static string[] MemoryToStringArray
Func<nint, string> customUnmarshaller
) => PtrToStringArray(input, input.Length / IntPtr.Size, customUnmarshaller);

private static unsafe string Utf8PtrToString(nint ptr)
/// <summary>
/// Gets the length of the given native string.
/// </summary>
/// <param name="ptr">The native string pointer.</param>
/// <param name="encoding">The encoding.</param>
/// <returns>The length of the string.</returns>
/// <remarks>
/// Note that this returns the length in characters. Namely, if a 16-bit character encoding is used, the actual
/// byte count will be double the return value from this function.
/// </remarks>
#if NET6_0_OR_GREATER
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe nuint StringLength(
nint ptr,
NativeStringEncoding encoding = NativeStringEncoding.Ansi
) =>
(nuint)(
encoding == NativeStringEncoding.LPWStr
? MemoryMarshal.CreateReadOnlySpanFromNullTerminated((char*)ptr).Length
: MemoryMarshal.CreateReadOnlySpanFromNullTerminated((byte*)ptr).Length
);
#else
public static unsafe nuint StringLength(
nint ptr,
NativeStringEncoding encoding = NativeStringEncoding.Ansi
)
{
var span = new Span<byte>((void*) ptr, int.MaxValue);
span = span.Slice(0, span.IndexOf(default(byte)));
if (span.Length == 0)
if (ptr == 0)
{
return string.Empty;
return 0;
}
nuint ret;
for (
ret = 0;
encoding == NativeStringEncoding.LPWStr
? ((char*)ptr)![ret] != 0
: ((byte*)ptr)![ret] != 0;
ret++
) { }
return ret;
}
#endif

fixed (byte* bytes = span)
{
return Encoding.UTF8.GetString(bytes, span.Length);
}
private static unsafe string Utf8PtrToString(nint ptr)
{
var len = (int)StringLength(ptr, NativeStringEncoding.UTF8);
return len == 0 ? string.Empty : Encoding.UTF8.GetString((byte*)ptr, len);
}

// "Unsafe" methods
Expand Down
10 changes: 6 additions & 4 deletions src/Core/Silk.NET.SilkTouch/Middlewares/StringMarshaller.cs
Original file line number Diff line number Diff line change
Expand Up @@ -119,10 +119,13 @@ public static void StringMarshaller(ref IMarshalContext ctx, Action next)
)
)
);
ctx.DeclareExtraRef(id); // readback
if (ctx.MethodSymbol.Parameters[index].RefKind is RefKind.Ref)
{
ctx.DeclareExtraRef(id); // readback
ctx.DeclareExtraRef(ctx.ParameterVariables[index]); // ptrToString
}
ctx.DeclareExtraRef(id); // free
ctx.SetParameterToVariable(index, id);
ctx.DeclareExtraRef(ctx.ParameterVariables[index]); // ptrToString
break;
case RefKind.Out:
{
Expand Down Expand Up @@ -263,8 +266,7 @@ public static void StringMarshaller(ref IMarshalContext ctx, Action next)

var marshalAs = ctx.ParameterMarshalOptions[index]?.UnmanagedType ?? Default;

if (ctx.MethodSymbol.Parameters[index].RefKind == RefKind.None ||
ctx.MethodSymbol.Parameters[index].RefKind == RefKind.Ref ||
if (ctx.MethodSymbol.Parameters[index].RefKind == RefKind.Ref ||
ctx.MethodSymbol.Parameters[index].RefKind == RefKind.Out)
{
var p2 = ctx.ResolveVariable(ctx.ParameterVariables[index]);
Expand Down
3 changes: 2 additions & 1 deletion src/Windowing/Silk.NET.GLFW/GlfwProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using Silk.NET.Core.Native;

namespace Silk.NET.GLFW
{
Expand All @@ -26,7 +27,7 @@ private static unsafe Glfw GetGlfw()
if (!glfw.Init())
{
var code = glfw.GetError(out var pDesc);
var len = new ReadOnlySpan<byte>(pDesc, int.MaxValue).IndexOf((byte) '\0');
var len = (int)SilkMarshal.StringLength((nint)pDesc);
var desc = len <= 0 ? "Unknown" : System.Text.Encoding.UTF8.GetString(pDesc, len);
throw new GlfwException($"GLFW Init failed, {code}: {desc}");
}
Expand Down

0 comments on commit f98e5e5

Please sign in to comment.