diff --git a/src/libraries/System.Private.Uri/src/System/IriHelper.cs b/src/libraries/System.Private.Uri/src/System/IriHelper.cs index a1d047e7d141ee..2b7013ac8e430b 100644 --- a/src/libraries/System.Private.Uri/src/System/IriHelper.cs +++ b/src/libraries/System.Private.Uri/src/System/IriHelper.cs @@ -113,8 +113,7 @@ internal static unsafe string EscapeUnescapeIri(char* pInput, int start, int end { // possibly utf8 encoded sequence of unicode int charactersRead = PercentEncodingHelper.UnescapePercentEncodedUTF8Sequence( - pInput + i, - end - i, + new ReadOnlySpan(pInput + i, end - i), ref dest, isQuery, iriParsing: true); diff --git a/src/libraries/System.Private.Uri/src/System/PercentEncodingHelper.cs b/src/libraries/System.Private.Uri/src/System/PercentEncodingHelper.cs index 5b88088b59933b..11cbc4f49d4f7e 100644 --- a/src/libraries/System.Private.Uri/src/System/PercentEncodingHelper.cs +++ b/src/libraries/System.Private.Uri/src/System/PercentEncodingHelper.cs @@ -3,14 +3,17 @@ using System.Buffers; using System.Diagnostics; +using System.Runtime.InteropServices; using System.Text; namespace System { internal static class PercentEncodingHelper { - public static unsafe int UnescapePercentEncodedUTF8Sequence(char* input, int length, ref ValueStringBuilder dest, bool isQuery, bool iriParsing) + public static int UnescapePercentEncodedUTF8Sequence(ReadOnlySpan input, ref ValueStringBuilder dest, bool isQuery, bool iriParsing) { + int length = input.Length; + // The following assertions rely on the input not mutating mid-operation, as is the case currently since callers are working with strings // If we start accepting input such as spans, this method must be audited to ensure no buffer overruns/infinite loops could occur @@ -85,7 +88,8 @@ public static unsafe int UnescapePercentEncodedUTF8Sequence(char* input, int len Debug.Assert(bytesLeftInBuffer < 4 || (fourByteBuffer & (BitConverter.IsLittleEndian ? 0x80000000 : 0x00000080)) != 0); uint temp = fourByteBuffer; // make a copy so that the *copy* (not the original) is marked address-taken - if (Rune.DecodeFromUtf8(new ReadOnlySpan(&temp, bytesLeftInBuffer), out Rune rune, out bytesConsumed) == OperationStatus.Done) + + if (Rune.DecodeFromUtf8(MemoryMarshal.AsBytes(new ReadOnlySpan(ref temp))[..bytesLeftInBuffer], out Rune rune, out bytesConsumed) == OperationStatus.Done) { Debug.Assert(bytesConsumed >= 2, $"Rune.DecodeFromUtf8 consumed {bytesConsumed} bytes, likely indicating input was modified concurrently during UnescapePercentEncodedUTF8Sequence's execution"); @@ -93,7 +97,7 @@ public static unsafe int UnescapePercentEncodedUTF8Sequence(char* input, int len { if (charsToCopy != 0) { - dest.Append(new ReadOnlySpan(input + totalCharsConsumed - charsToCopy, charsToCopy)); + dest.Append(input.Slice(totalCharsConsumed - charsToCopy, charsToCopy)); charsToCopy = 0; } @@ -167,7 +171,8 @@ public static unsafe int UnescapePercentEncodedUTF8Sequence(char* input, int len return totalCharsConsumed; bytesLeftInBuffer *= 3; - dest.Append(new ReadOnlySpan(input + totalCharsConsumed - charsToCopy, charsToCopy + bytesLeftInBuffer)); + + dest.Append(input.Slice(totalCharsConsumed - charsToCopy, charsToCopy + bytesLeftInBuffer)); return totalCharsConsumed + bytesLeftInBuffer; } } diff --git a/src/libraries/System.Private.Uri/src/System/UriExt.cs b/src/libraries/System.Private.Uri/src/System/UriExt.cs index 739338060247c9..24de5ab699e950 100644 --- a/src/libraries/System.Private.Uri/src/System/UriExt.cs +++ b/src/libraries/System.Private.Uri/src/System/UriExt.cs @@ -1027,17 +1027,7 @@ internal bool IsBaseOfHelper(Uri uriLink) string self = GetParts(ComponentsToCompare, UriFormat.SafeUnescaped); string other = uriLink.GetParts(ComponentsToCompare, UriFormat.SafeUnescaped); - unsafe - { - fixed (char* selfPtr = self) - { - fixed (char* otherPtr = other) - { - return UriHelper.TestForSubPath(selfPtr, self.Length, otherPtr, other.Length, - IsUncOrDosPath || uriLink.IsUncOrDosPath); - } - } - } + return UriHelper.TestForSubPath(self, other, IsUncOrDosPath || uriLink.IsUncOrDosPath); } // diff --git a/src/libraries/System.Private.Uri/src/System/UriHelper.cs b/src/libraries/System.Private.Uri/src/System/UriHelper.cs index e268da9e2f6286..938940883f84a4 100644 --- a/src/libraries/System.Private.Uri/src/System/UriHelper.cs +++ b/src/libraries/System.Private.Uri/src/System/UriHelper.cs @@ -56,8 +56,7 @@ public static string NormalizeAndConcat(string? start, ReadOnlySpan toNorm // ASSUMES that strings like http://host/Path/Path/MoreDir/../../ have been canonicalized before going to this method. // ASSUMES that back slashes already have been converted if applicable. // - internal static unsafe bool TestForSubPath(char* selfPtr, int selfLength, char* otherPtr, int otherLength, - bool ignoreCase) + internal static bool TestForSubPath(ReadOnlySpan self, ReadOnlySpan other, bool ignoreCase) { int i = 0; char chSelf; @@ -65,10 +64,10 @@ internal static unsafe bool TestForSubPath(char* selfPtr, int selfLength, char* bool AllSameBeforeSlash = true; - for (; i < selfLength && i < otherLength; ++i) + for (; i < self.Length && i < other.Length; ++i) { - chSelf = *(selfPtr + i); - chOther = *(otherPtr + i); + chSelf = self[i]; + chOther = other[i]; if (chSelf == '?' || chSelf == '#') { @@ -118,9 +117,9 @@ internal static unsafe bool TestForSubPath(char* selfPtr, int selfLength, char* } // If self is longer then it must not have any more path segments - for (; i < selfLength; ++i) + for (; i < self.Length; ++i) { - if ((chSelf = *(selfPtr + i)) == '?' || chSelf == '#') + if ((chSelf = self[i]) == '?' || chSelf == '#') { return true; } @@ -507,8 +506,7 @@ internal static unsafe void UnescapeString(char* pStr, int start, int end, ref V { // Unicode int charactersRead = PercentEncodingHelper.UnescapePercentEncodedUTF8Sequence( - pStr + next, - end - next, + new ReadOnlySpan(pStr + next, end - next), ref dest, isQuery, iriParsing);