Skip to content

Commit c509e14

Browse files
committed
core: page-safe GetUtf8Span via CreateReadOnlySpanFromNullTerminated
Vectorized IndexOf over an int.MaxValue-sized span can fault when the null-terminated string sits within ~64 bytes of an unmapped page boundary, even though the terminator is present. Use the page-safe strlen-based API for the unknown-length path.
1 parent 623c1b3 commit c509e14

1 file changed

Lines changed: 18 additions & 22 deletions

File tree

sources/core/Stride.Core/Unsafe/StringMarshal.cs

Lines changed: 18 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -179,9 +179,16 @@ public static ReadOnlySpan<byte> GetUtf8Span(this string source)
179179
/// </returns>
180180
[MethodImpl(MethodImplOptions.AggressiveInlining)]
181181
public static ReadOnlySpan<byte> GetUtf8Span(byte* source, int maxLength = -1)
182-
=> source is not null
183-
? GetUtf8Span(in source[0], maxLength)
184-
: null;
182+
{
183+
if (source is null)
184+
return null;
185+
// Page-safe scan when the length is unknown: a vectorized IndexOf over an
186+
// int.MaxValue-sized span can fault when the string sits within ~64 bytes
187+
// of an unmapped page boundary, even if the null terminator is present.
188+
if (maxLength < 0)
189+
return MemoryMarshal.CreateReadOnlySpanFromNullTerminated(source);
190+
return GetUtf8Span(in source[0], maxLength);
191+
}
185192

186193
/// <summary>
187194
/// Gets a span for a null-terminated UTF-8 character sequence.
@@ -197,27 +204,16 @@ public static ReadOnlySpan<byte> GetUtf8Span(byte* source, int maxLength = -1)
197204
[MethodImpl(MethodImplOptions.AggressiveInlining)]
198205
public static ReadOnlySpan<byte> GetUtf8Span(in byte source, int maxLength = -1)
199206
{
200-
ReadOnlySpan<byte> result;
207+
if (IsNullRef(in source))
208+
return null;
201209

202-
if (!IsNullRef(in source))
203-
{
204-
if (maxLength < 0)
205-
maxLength = int.MaxValue;
210+
if (maxLength < 0)
211+
return MemoryMarshal.CreateReadOnlySpanFromNullTerminated(
212+
(byte*) Unsafe.AsPointer(ref Unsafe.AsRef(in source)));
206213

207-
result = CreateReadOnlySpan(in source, maxLength);
208-
var length = result.IndexOf((byte) '\0');
209-
210-
if (length != -1)
211-
{
212-
result = result[..length];
213-
}
214-
}
215-
else
216-
{
217-
result = null;
218-
}
219-
220-
return result;
214+
var result = CreateReadOnlySpan(in source, maxLength);
215+
var length = result.IndexOf((byte) '\0');
216+
return length != -1 ? result[..length] : result;
221217
}
222218

223219
/// <summary>

0 commit comments

Comments
 (0)