Skip to content

Commit f98e5e5

Browse files
authored
Fix AVE in PtrToString on .NET 8 & remove unnecessary marshalling (#1990)
* Fix AVE in PtrToString on .NET 8 & remove unnecessary marshalling * Review comments
1 parent 4f76a9f commit f98e5e5

File tree

3 files changed

+51
-14
lines changed

3 files changed

+51
-14
lines changed

src/Core/Silk.NET.Core/Native/SilkMarshal.cs

Lines changed: 43 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -512,19 +512,53 @@ public static string[] MemoryToStringArray
512512
Func<nint, string> customUnmarshaller
513513
) => PtrToStringArray(input, input.Length / IntPtr.Size, customUnmarshaller);
514514

515-
private static unsafe string Utf8PtrToString(nint ptr)
515+
/// <summary>
516+
/// Gets the length of the given native string.
517+
/// </summary>
518+
/// <param name="ptr">The native string pointer.</param>
519+
/// <param name="encoding">The encoding.</param>
520+
/// <returns>The length of the string.</returns>
521+
/// <remarks>
522+
/// Note that this returns the length in characters. Namely, if a 16-bit character encoding is used, the actual
523+
/// byte count will be double the return value from this function.
524+
/// </remarks>
525+
#if NET6_0_OR_GREATER
526+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
527+
public static unsafe nuint StringLength(
528+
nint ptr,
529+
NativeStringEncoding encoding = NativeStringEncoding.Ansi
530+
) =>
531+
(nuint)(
532+
encoding == NativeStringEncoding.LPWStr
533+
? MemoryMarshal.CreateReadOnlySpanFromNullTerminated((char*)ptr).Length
534+
: MemoryMarshal.CreateReadOnlySpanFromNullTerminated((byte*)ptr).Length
535+
);
536+
#else
537+
public static unsafe nuint StringLength(
538+
nint ptr,
539+
NativeStringEncoding encoding = NativeStringEncoding.Ansi
540+
)
516541
{
517-
var span = new Span<byte>((void*) ptr, int.MaxValue);
518-
span = span.Slice(0, span.IndexOf(default(byte)));
519-
if (span.Length == 0)
542+
if (ptr == 0)
520543
{
521-
return string.Empty;
544+
return 0;
522545
}
546+
nuint ret;
547+
for (
548+
ret = 0;
549+
encoding == NativeStringEncoding.LPWStr
550+
? ((char*)ptr)![ret] != 0
551+
: ((byte*)ptr)![ret] != 0;
552+
ret++
553+
) { }
554+
return ret;
555+
}
556+
#endif
523557

524-
fixed (byte* bytes = span)
525-
{
526-
return Encoding.UTF8.GetString(bytes, span.Length);
527-
}
558+
private static unsafe string Utf8PtrToString(nint ptr)
559+
{
560+
var len = (int)StringLength(ptr, NativeStringEncoding.UTF8);
561+
return len == 0 ? string.Empty : Encoding.UTF8.GetString((byte*)ptr, len);
528562
}
529563

530564
// "Unsafe" methods

src/Core/Silk.NET.SilkTouch/Middlewares/StringMarshaller.cs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -119,10 +119,13 @@ public static void StringMarshaller(ref IMarshalContext ctx, Action next)
119119
)
120120
)
121121
);
122-
ctx.DeclareExtraRef(id); // readback
122+
if (ctx.MethodSymbol.Parameters[index].RefKind is RefKind.Ref)
123+
{
124+
ctx.DeclareExtraRef(id); // readback
125+
ctx.DeclareExtraRef(ctx.ParameterVariables[index]); // ptrToString
126+
}
123127
ctx.DeclareExtraRef(id); // free
124128
ctx.SetParameterToVariable(index, id);
125-
ctx.DeclareExtraRef(ctx.ParameterVariables[index]); // ptrToString
126129
break;
127130
case RefKind.Out:
128131
{
@@ -263,8 +266,7 @@ public static void StringMarshaller(ref IMarshalContext ctx, Action next)
263266

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

266-
if (ctx.MethodSymbol.Parameters[index].RefKind == RefKind.None ||
267-
ctx.MethodSymbol.Parameters[index].RefKind == RefKind.Ref ||
269+
if (ctx.MethodSymbol.Parameters[index].RefKind == RefKind.Ref ||
268270
ctx.MethodSymbol.Parameters[index].RefKind == RefKind.Out)
269271
{
270272
var p2 = ctx.ResolveVariable(ctx.ParameterVariables[index]);

src/Windowing/Silk.NET.GLFW/GlfwProvider.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
using System;
5+
using Silk.NET.Core.Native;
56

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

0 commit comments

Comments
 (0)