From 0dfae8c99b5167641b071392e4c47da6aa6dfbb0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 30 Jul 2025 13:01:32 +0000 Subject: [PATCH 01/15] Initial plan From 4a6c5e5fc5fd1772bc078a47c6f3d0a83a94c495 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 30 Jul 2025 13:37:04 +0000 Subject: [PATCH 02/15] Fix Version deserialization to be more strict about edge cases Co-authored-by: eiriktsarpalis <2813363+eiriktsarpalis@users.noreply.github.com> --- .../Converters/Value/VersionConverter.cs | 45 +++++++++++++++++++ .../Serialization/Value.ReadTests.cs | 7 +++ 2 files changed, 52 insertions(+) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/VersionConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/VersionConverter.cs index 5f3757bb8ae926..dad6a9d71b480e 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/VersionConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/VersionConverter.cs @@ -17,6 +17,35 @@ internal sealed class VersionConverter : JsonPrimitiveConverter private const int MaximumEscapedVersionLength = JsonConstants.MaxExpansionFactorWhileEscaping * MaximumVersionLength; #endif + private static bool IsValidVersionFormat(ReadOnlySpan source) + { + // Check for plus signs anywhere in the string + if (source.IndexOf('+') >= 0) + { + return false; + } + + // Check for whitespace adjacent to dots + for (int i = 0; i < source.Length; i++) + { + if (source[i] == '.') + { + // Check for whitespace before the dot + if (i > 0 && char.IsWhiteSpace(source[i - 1])) + { + return false; + } + // Check for whitespace after the dot + if (i < source.Length - 1 && char.IsWhiteSpace(source[i + 1])) + { + return false; + } + } + } + + return true; + } + public override Version? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType is JsonTokenType.Null) @@ -55,6 +84,14 @@ private static Version ReadCore(ref Utf8JsonReader reader) ThrowHelper.ThrowFormatException(DataType.Version); } + // Additional validation to be more strict than Version.TryParse: + // - Reject plus signs anywhere in the string + // - Reject whitespace adjacent to dots + if (!IsValidVersionFormat(source)) + { + ThrowHelper.ThrowFormatException(DataType.Version); + } + if (Version.TryParse(source, out Version? result)) { return result; @@ -69,6 +106,14 @@ private static Version ReadCore(ref Utf8JsonReader reader) // since Version.TryParse allows them and silently parses input to Version ThrowHelper.ThrowFormatException(DataType.Version); } + + // Additional validation to be more strict than Version.TryParse: + // - Reject plus signs anywhere in the string + // - Reject whitespace adjacent to dots + if (!string.IsNullOrEmpty(versionString) && !IsValidVersionFormat(versionString.AsSpan())) + { + ThrowHelper.ThrowFormatException(DataType.Version); + } if (Version.TryParse(versionString, out Version? result)) { return result; diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/Value.ReadTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/Value.ReadTests.cs index 1e1b585ea33c47..7dae5d663ea4c7 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/Value.ReadTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/Value.ReadTests.cs @@ -358,6 +358,13 @@ public static void Version_Read_Success(string json, string? actual = null) [InlineData(" 1.2.3.4")] //Valid but has leading whitespace [InlineData("1.2.3.4 ")] //Valid but has trailing whitespace [InlineData(" 1.2.3.4 ")] //Valid but has trailing and leading whitespaces + [InlineData("1.+1")] //Plus sign in second component should be rejected + [InlineData("1 .1")] //Whitespace before dot should be rejected + [InlineData("1. 1")] //Whitespace after dot should be rejected + [InlineData("1 . +1")] //Whitespace around dot and plus sign should be rejected + [InlineData("1.+2.3")] //Plus sign in second component with more components + [InlineData("1.2. 3")] //Whitespace after second dot + [InlineData("1 .2.3")] //Whitespace before first dot [InlineData("{}", false)] [InlineData("[]", false)] [InlineData("true", false)] From 4d365373289dadd649b762f7390eb36126a07ddd Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 30 Jul 2025 15:00:42 +0000 Subject: [PATCH 03/15] Make Version JSON deserialization more permissive to match Version.Parse behavior Co-authored-by: eiriktsarpalis <2813363+eiriktsarpalis@users.noreply.github.com> --- .../Converters/Value/VersionConverter.cs | 62 ------------------- .../Serialization/Value.ReadTests.cs | 18 +++--- 2 files changed, 8 insertions(+), 72 deletions(-) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/VersionConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/VersionConverter.cs index dad6a9d71b480e..2b82787ea383bc 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/VersionConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/VersionConverter.cs @@ -17,35 +17,6 @@ internal sealed class VersionConverter : JsonPrimitiveConverter private const int MaximumEscapedVersionLength = JsonConstants.MaxExpansionFactorWhileEscaping * MaximumVersionLength; #endif - private static bool IsValidVersionFormat(ReadOnlySpan source) - { - // Check for plus signs anywhere in the string - if (source.IndexOf('+') >= 0) - { - return false; - } - - // Check for whitespace adjacent to dots - for (int i = 0; i < source.Length; i++) - { - if (source[i] == '.') - { - // Check for whitespace before the dot - if (i > 0 && char.IsWhiteSpace(source[i - 1])) - { - return false; - } - // Check for whitespace after the dot - if (i < source.Length - 1 && char.IsWhiteSpace(source[i + 1])) - { - return false; - } - } - } - - return true; - } - public override Version? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType is JsonTokenType.Null) @@ -75,45 +46,12 @@ private static Version ReadCore(ref Utf8JsonReader reader) int bytesWritten = reader.CopyString(charBuffer); ReadOnlySpan source = charBuffer.Slice(0, bytesWritten); - if (!char.IsDigit(source[0]) || !char.IsDigit(source[^1])) - { - // Since leading and trailing whitespaces are forbidden throughout System.Text.Json converters - // we need to make sure that our input doesn't have them, - // and if it has - we need to throw, to match behaviour of other converters - // since Version.TryParse allows them and silently parses input to Version - ThrowHelper.ThrowFormatException(DataType.Version); - } - - // Additional validation to be more strict than Version.TryParse: - // - Reject plus signs anywhere in the string - // - Reject whitespace adjacent to dots - if (!IsValidVersionFormat(source)) - { - ThrowHelper.ThrowFormatException(DataType.Version); - } - if (Version.TryParse(source, out Version? result)) { return result; } #else string? versionString = reader.GetString(); - if (!string.IsNullOrEmpty(versionString) && (!char.IsDigit(versionString[0]) || !char.IsDigit(versionString[versionString.Length - 1]))) - { - // Since leading and trailing whitespaces are forbidden throughout System.Text.Json converters - // we need to make sure that our input doesn't have them, - // and if it has - we need to throw, to match behaviour of other converters - // since Version.TryParse allows them and silently parses input to Version - ThrowHelper.ThrowFormatException(DataType.Version); - } - - // Additional validation to be more strict than Version.TryParse: - // - Reject plus signs anywhere in the string - // - Reject whitespace adjacent to dots - if (!string.IsNullOrEmpty(versionString) && !IsValidVersionFormat(versionString.AsSpan())) - { - ThrowHelper.ThrowFormatException(DataType.Version); - } if (Version.TryParse(versionString, out Version? result)) { return result; diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/Value.ReadTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/Value.ReadTests.cs index 7dae5d663ea4c7..1f1b0f19ca34a9 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/Value.ReadTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/Value.ReadTests.cs @@ -336,6 +336,14 @@ public static void ValueFail() [InlineData("2147483647.2147483647.2147483647.2147483647")] [InlineData("\\u0032\\u0031\\u0034\\u0037\\u0034\\u0038\\u0033\\u0036\\u0034\\u0037\\u002e\\u0032\\u0031\\u0034\\u0037\\u0034\\u0038\\u0033\\u0036\\u0034\\u0037\\u002e\\u0032\\u0031\\u0034\\u0037\\u0034\\u0038\\u0033\\u0036\\u0034\\u0037\\u002e\\u0032\\u0031\\u0034\\u0037\\u0034\\u0038\\u0033\\u0036\\u0034\\u0037", "2147483647.2147483647.2147483647.2147483647")] + [InlineData(" 1.2.3.4", "1.2.3.4")] // Leading whitespace should now be accepted + [InlineData("1.2.3.4 ", "1.2.3.4")] // Trailing whitespace should now be accepted + [InlineData(" 1.2.3.4 ", "1.2.3.4")] // Leading and trailing whitespace should now be accepted + [InlineData("+1.1", "1.1")] // Leading plus should now be accepted + [InlineData("1.+1", "1.1")] // Plus in components should work as before + [InlineData("1 .1", "1.1")] // Whitespace before dot should work as before + [InlineData("1. 1", "1.1")] // Whitespace after dot should work as before + [InlineData("1 . +1", "1.1")] // Combined whitespace and plus should work as before public static void Version_Read_Success(string json, string? actual = null) { actual ??= json; @@ -355,16 +363,6 @@ public static void Version_Read_Success(string json, string? actual = null) [InlineData("-2147483648.-2147483648.-2147483648.-2147483648")] [InlineData("1.-1")] [InlineData("1")] - [InlineData(" 1.2.3.4")] //Valid but has leading whitespace - [InlineData("1.2.3.4 ")] //Valid but has trailing whitespace - [InlineData(" 1.2.3.4 ")] //Valid but has trailing and leading whitespaces - [InlineData("1.+1")] //Plus sign in second component should be rejected - [InlineData("1 .1")] //Whitespace before dot should be rejected - [InlineData("1. 1")] //Whitespace after dot should be rejected - [InlineData("1 . +1")] //Whitespace around dot and plus sign should be rejected - [InlineData("1.+2.3")] //Plus sign in second component with more components - [InlineData("1.2. 3")] //Whitespace after second dot - [InlineData("1 .2.3")] //Whitespace before first dot [InlineData("{}", false)] [InlineData("[]", false)] [InlineData("true", false)] From c14d2ce192dd5aeae065f1a055daafde5e2d700a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 30 Jul 2025 16:17:30 +0000 Subject: [PATCH 04/15] Remove length check and use conditional stackalloc with ArrayPool fallback for VersionConverter Co-authored-by: eiriktsarpalis <2813363+eiriktsarpalis@users.noreply.github.com> --- .../Converters/Value/VersionConverter.cs | 39 +++++++++++++++---- .../Serialization/Value.ReadTests.cs | 8 ++-- 2 files changed, 35 insertions(+), 12 deletions(-) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/VersionConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/VersionConverter.cs index 2b82787ea383bc..5cb31deaab559e 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/VersionConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/VersionConverter.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Buffers; using System.Diagnostics; using System.Text.Json.Nodes; using System.Text.Json.Schema; @@ -13,8 +14,6 @@ internal sealed class VersionConverter : JsonPrimitiveConverter private const int MinimumVersionLength = 3; // 0.0 private const int MaximumVersionLength = 43; // 2147483647.2147483647.2147483647.2147483647 - - private const int MaximumEscapedVersionLength = JsonConstants.MaxExpansionFactorWhileEscaping * MaximumVersionLength; #endif public override Version? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) @@ -37,21 +36,45 @@ private static Version ReadCore(ref Utf8JsonReader reader) Debug.Assert(reader.TokenType is JsonTokenType.PropertyName or JsonTokenType.String); #if NET - if (!JsonHelpers.IsInRangeInclusive(reader.ValueLength, MinimumVersionLength, MaximumEscapedVersionLength)) + int bufferLength = reader.ValueLength; + char[]? rentedBuffer = null; + Span charBuffer = bufferLength <= JsonConstants.StackallocCharThreshold + ? stackalloc char[JsonConstants.StackallocCharThreshold] + : (rentedBuffer = ArrayPool.Shared.Rent(bufferLength)); + + int bytesWritten = reader.CopyString(charBuffer); + ReadOnlySpan source = charBuffer.Slice(0, bytesWritten); + + // Enforce leading and trailing whitespace rejection + if (source.Length > 0 && (char.IsWhiteSpace(source[0]) || char.IsWhiteSpace(source[^1]))) { + if (rentedBuffer is not null) + { + ArrayPool.Shared.Return(rentedBuffer); + } ThrowHelper.ThrowFormatException(DataType.Version); } - Span charBuffer = stackalloc char[MaximumEscapedVersionLength]; - int bytesWritten = reader.CopyString(charBuffer); - ReadOnlySpan source = charBuffer.Slice(0, bytesWritten); + bool success = Version.TryParse(source, out Version? result); - if (Version.TryParse(source, out Version? result)) + if (rentedBuffer is not null) { - return result; + ArrayPool.Shared.Return(rentedBuffer); + } + + if (success) + { + return result!; } #else string? versionString = reader.GetString(); + + // Enforce leading and trailing whitespace rejection + if (!string.IsNullOrEmpty(versionString) && (char.IsWhiteSpace(versionString[0]) || char.IsWhiteSpace(versionString[versionString.Length - 1]))) + { + ThrowHelper.ThrowFormatException(DataType.Version); + } + if (Version.TryParse(versionString, out Version? result)) { return result; diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/Value.ReadTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/Value.ReadTests.cs index 1f1b0f19ca34a9..cc57fd2333c4e6 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/Value.ReadTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/Value.ReadTests.cs @@ -336,10 +336,6 @@ public static void ValueFail() [InlineData("2147483647.2147483647.2147483647.2147483647")] [InlineData("\\u0032\\u0031\\u0034\\u0037\\u0034\\u0038\\u0033\\u0036\\u0034\\u0037\\u002e\\u0032\\u0031\\u0034\\u0037\\u0034\\u0038\\u0033\\u0036\\u0034\\u0037\\u002e\\u0032\\u0031\\u0034\\u0037\\u0034\\u0038\\u0033\\u0036\\u0034\\u0037\\u002e\\u0032\\u0031\\u0034\\u0037\\u0034\\u0038\\u0033\\u0036\\u0034\\u0037", "2147483647.2147483647.2147483647.2147483647")] - [InlineData(" 1.2.3.4", "1.2.3.4")] // Leading whitespace should now be accepted - [InlineData("1.2.3.4 ", "1.2.3.4")] // Trailing whitespace should now be accepted - [InlineData(" 1.2.3.4 ", "1.2.3.4")] // Leading and trailing whitespace should now be accepted - [InlineData("+1.1", "1.1")] // Leading plus should now be accepted [InlineData("1.+1", "1.1")] // Plus in components should work as before [InlineData("1 .1", "1.1")] // Whitespace before dot should work as before [InlineData("1. 1", "1.1")] // Whitespace after dot should work as before @@ -356,6 +352,10 @@ public static void Version_Read_Success(string json, string? actual = null) [InlineData("")] [InlineData(" ")] [InlineData(" ")] + [InlineData(" 1.2.3.4")] // Leading whitespace should be rejected + [InlineData("1.2.3.4 ")] // Trailing whitespace should be rejected + [InlineData(" 1.2.3.4 ")] // Leading and trailing whitespace should be rejected + [InlineData("+1.1")] // Leading plus should be rejected [InlineData("2147483648.2147483648.2147483648.2147483648")] //int.MaxValue + 1 [InlineData("2147483647.2147483647.2147483647.21474836477")] // Slightly bigger in size than max length of Version [InlineData("-2147483648.-2147483648")] From 6f6b2f5765ee449afe4673a4621426f45ea6d22f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 30 Jul 2025 16:52:36 +0000 Subject: [PATCH 05/15] Remove added comments to maintain original code style Co-authored-by: eiriktsarpalis <2813363+eiriktsarpalis@users.noreply.github.com> --- .../Json/Serialization/Converters/Value/VersionConverter.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/VersionConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/VersionConverter.cs index 5cb31deaab559e..d41e6db344a77f 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/VersionConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/VersionConverter.cs @@ -45,8 +45,7 @@ private static Version ReadCore(ref Utf8JsonReader reader) int bytesWritten = reader.CopyString(charBuffer); ReadOnlySpan source = charBuffer.Slice(0, bytesWritten); - // Enforce leading and trailing whitespace rejection - if (source.Length > 0 && (char.IsWhiteSpace(source[0]) || char.IsWhiteSpace(source[^1]))) + if (source.Length > 0 && (char.IsWhiteSpace(source[0]) || char.IsWhiteSpace(source[^1]) || source[0] == '+')) { if (rentedBuffer is not null) { @@ -69,8 +68,7 @@ private static Version ReadCore(ref Utf8JsonReader reader) #else string? versionString = reader.GetString(); - // Enforce leading and trailing whitespace rejection - if (!string.IsNullOrEmpty(versionString) && (char.IsWhiteSpace(versionString[0]) || char.IsWhiteSpace(versionString[versionString.Length - 1]))) + if (!string.IsNullOrEmpty(versionString) && (char.IsWhiteSpace(versionString[0]) || char.IsWhiteSpace(versionString[versionString.Length - 1]) || versionString[0] == '+')) { ThrowHelper.ThrowFormatException(DataType.Version); } From cdb6faeedd93d59f770d727f5f97fd218e884741 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 30 Jul 2025 17:24:34 +0000 Subject: [PATCH 06/15] Move buffer return into finally block for VersionConverter Co-authored-by: eiriktsarpalis <2813363+eiriktsarpalis@users.noreply.github.com> --- .../Converters/Value/VersionConverter.cs | 37 ++++++++++--------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/VersionConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/VersionConverter.cs index d41e6db344a77f..8664af6a1805c0 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/VersionConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/VersionConverter.cs @@ -38,32 +38,33 @@ private static Version ReadCore(ref Utf8JsonReader reader) #if NET int bufferLength = reader.ValueLength; char[]? rentedBuffer = null; - Span charBuffer = bufferLength <= JsonConstants.StackallocCharThreshold - ? stackalloc char[JsonConstants.StackallocCharThreshold] - : (rentedBuffer = ArrayPool.Shared.Rent(bufferLength)); + try + { + Span charBuffer = bufferLength <= JsonConstants.StackallocCharThreshold + ? stackalloc char[JsonConstants.StackallocCharThreshold] + : (rentedBuffer = ArrayPool.Shared.Rent(bufferLength)); - int bytesWritten = reader.CopyString(charBuffer); - ReadOnlySpan source = charBuffer.Slice(0, bytesWritten); + int bytesWritten = reader.CopyString(charBuffer); + ReadOnlySpan source = charBuffer.Slice(0, bytesWritten); - if (source.Length > 0 && (char.IsWhiteSpace(source[0]) || char.IsWhiteSpace(source[^1]) || source[0] == '+')) - { - if (rentedBuffer is not null) + if (source.Length > 0 && (char.IsWhiteSpace(source[0]) || char.IsWhiteSpace(source[^1]) || source[0] == '+')) { - ArrayPool.Shared.Return(rentedBuffer); + ThrowHelper.ThrowFormatException(DataType.Version); } - ThrowHelper.ThrowFormatException(DataType.Version); - } - bool success = Version.TryParse(source, out Version? result); + bool success = Version.TryParse(source, out Version? result); - if (rentedBuffer is not null) - { - ArrayPool.Shared.Return(rentedBuffer); + if (success) + { + return result!; + } } - - if (success) + finally { - return result!; + if (rentedBuffer is not null) + { + ArrayPool.Shared.Return(rentedBuffer); + } } #else string? versionString = reader.GetString(); From 28e315f032b6a2f21fffc47d9e835230d44b5203 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 31 Jul 2025 10:12:07 +0000 Subject: [PATCH 07/15] Reinstate original comments explaining validation logic Co-authored-by: eiriktsarpalis <2813363+eiriktsarpalis@users.noreply.github.com> --- .../Serialization/Converters/Value/VersionConverter.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/VersionConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/VersionConverter.cs index 8664af6a1805c0..3839ea35124321 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/VersionConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/VersionConverter.cs @@ -49,6 +49,10 @@ private static Version ReadCore(ref Utf8JsonReader reader) if (source.Length > 0 && (char.IsWhiteSpace(source[0]) || char.IsWhiteSpace(source[^1]) || source[0] == '+')) { + // Since leading and trailing whitespaces are forbidden throughout System.Text.Json converters + // we need to make sure that our input doesn't have them, + // and if it has - we need to throw, to match behaviour of other converters + // since Version.TryParse allows them and silently parses input to Version ThrowHelper.ThrowFormatException(DataType.Version); } @@ -71,6 +75,10 @@ private static Version ReadCore(ref Utf8JsonReader reader) if (!string.IsNullOrEmpty(versionString) && (char.IsWhiteSpace(versionString[0]) || char.IsWhiteSpace(versionString[versionString.Length - 1]) || versionString[0] == '+')) { + // Since leading and trailing whitespaces are forbidden throughout System.Text.Json converters + // we need to make sure that our input doesn't have them, + // and if it has - we need to throw, to match behaviour of other converters + // since Version.TryParse allows them and silently parses input to Version ThrowHelper.ThrowFormatException(DataType.Version); } From da19cc341e3cc40748e31f7a69374f5ef0ee17ab Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 31 Jul 2025 11:19:28 +0000 Subject: [PATCH 08/15] Remove leading plus sign validation check from VersionConverter Co-authored-by: eiriktsarpalis <2813363+eiriktsarpalis@users.noreply.github.com> --- .../Json/Serialization/Converters/Value/VersionConverter.cs | 4 ++-- .../System.Text.Json.Tests/Serialization/Value.ReadTests.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/VersionConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/VersionConverter.cs index 3839ea35124321..0eb1d5db9654e2 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/VersionConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/VersionConverter.cs @@ -47,7 +47,7 @@ private static Version ReadCore(ref Utf8JsonReader reader) int bytesWritten = reader.CopyString(charBuffer); ReadOnlySpan source = charBuffer.Slice(0, bytesWritten); - if (source.Length > 0 && (char.IsWhiteSpace(source[0]) || char.IsWhiteSpace(source[^1]) || source[0] == '+')) + if (source.Length > 0 && (char.IsWhiteSpace(source[0]) || char.IsWhiteSpace(source[^1]))) { // Since leading and trailing whitespaces are forbidden throughout System.Text.Json converters // we need to make sure that our input doesn't have them, @@ -73,7 +73,7 @@ private static Version ReadCore(ref Utf8JsonReader reader) #else string? versionString = reader.GetString(); - if (!string.IsNullOrEmpty(versionString) && (char.IsWhiteSpace(versionString[0]) || char.IsWhiteSpace(versionString[versionString.Length - 1]) || versionString[0] == '+')) + if (!string.IsNullOrEmpty(versionString) && (char.IsWhiteSpace(versionString[0]) || char.IsWhiteSpace(versionString[versionString.Length - 1]))) { // Since leading and trailing whitespaces are forbidden throughout System.Text.Json converters // we need to make sure that our input doesn't have them, diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/Value.ReadTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/Value.ReadTests.cs index cc57fd2333c4e6..d235b69f9bfff6 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/Value.ReadTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/Value.ReadTests.cs @@ -340,6 +340,7 @@ public static void ValueFail() [InlineData("1 .1", "1.1")] // Whitespace before dot should work as before [InlineData("1. 1", "1.1")] // Whitespace after dot should work as before [InlineData("1 . +1", "1.1")] // Combined whitespace and plus should work as before + [InlineData("+1.1", "1.1")] // Leading plus should work public static void Version_Read_Success(string json, string? actual = null) { actual ??= json; @@ -355,7 +356,6 @@ public static void Version_Read_Success(string json, string? actual = null) [InlineData(" 1.2.3.4")] // Leading whitespace should be rejected [InlineData("1.2.3.4 ")] // Trailing whitespace should be rejected [InlineData(" 1.2.3.4 ")] // Leading and trailing whitespace should be rejected - [InlineData("+1.1")] // Leading plus should be rejected [InlineData("2147483648.2147483648.2147483648.2147483648")] //int.MaxValue + 1 [InlineData("2147483647.2147483647.2147483647.21474836477")] // Slightly bigger in size than max length of Version [InlineData("-2147483648.-2147483648")] From c4b7c8f71fcd3a400e52d12d796b6731716deaf3 Mon Sep 17 00:00:00 2001 From: Eirik Tsarpalis Date: Thu, 31 Jul 2025 16:10:24 +0300 Subject: [PATCH 09/15] Update src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/VersionConverter.cs --- .../Text/Json/Serialization/Converters/Value/VersionConverter.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/VersionConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/VersionConverter.cs index 0eb1d5db9654e2..272bbf17f2c39f 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/VersionConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/VersionConverter.cs @@ -72,7 +72,6 @@ private static Version ReadCore(ref Utf8JsonReader reader) } #else string? versionString = reader.GetString(); - if (!string.IsNullOrEmpty(versionString) && (char.IsWhiteSpace(versionString[0]) || char.IsWhiteSpace(versionString[versionString.Length - 1]))) { // Since leading and trailing whitespaces are forbidden throughout System.Text.Json converters From 57418411b14e588335b05641265a031486b3fed3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 31 Jul 2025 14:09:19 +0000 Subject: [PATCH 10/15] Simplify whitespace validation conditions in VersionConverter Co-authored-by: eiriktsarpalis <2813363+eiriktsarpalis@users.noreply.github.com> --- .../Json/Serialization/Converters/Value/VersionConverter.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/VersionConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/VersionConverter.cs index 272bbf17f2c39f..40ba30410b240e 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/VersionConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/VersionConverter.cs @@ -47,7 +47,7 @@ private static Version ReadCore(ref Utf8JsonReader reader) int bytesWritten = reader.CopyString(charBuffer); ReadOnlySpan source = charBuffer.Slice(0, bytesWritten); - if (source.Length > 0 && (char.IsWhiteSpace(source[0]) || char.IsWhiteSpace(source[^1]))) + if (source.IsEmpty || char.IsWhiteSpace(source[0]) || char.IsWhiteSpace(source[^1])) { // Since leading and trailing whitespaces are forbidden throughout System.Text.Json converters // we need to make sure that our input doesn't have them, @@ -72,7 +72,7 @@ private static Version ReadCore(ref Utf8JsonReader reader) } #else string? versionString = reader.GetString(); - if (!string.IsNullOrEmpty(versionString) && (char.IsWhiteSpace(versionString[0]) || char.IsWhiteSpace(versionString[versionString.Length - 1]))) + if (string.IsNullOrEmpty(versionString) || char.IsWhiteSpace(versionString[0]) || char.IsWhiteSpace(versionString[versionString.Length - 1])) { // Since leading and trailing whitespaces are forbidden throughout System.Text.Json converters // we need to make sure that our input doesn't have them, From a1bb3588383371f4b16167989222a4e47c32dffc Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 31 Jul 2025 14:52:13 +0000 Subject: [PATCH 11/15] Remove MinimumVersionLength constant and rename MaximumVersionLength to MaximumFormattedVersionLength Co-authored-by: eiriktsarpalis <2813363+eiriktsarpalis@users.noreply.github.com> --- .../Converters/Value/VersionConverter.cs | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/VersionConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/VersionConverter.cs index 40ba30410b240e..7e135cf6cb9118 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/VersionConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/VersionConverter.cs @@ -11,9 +11,7 @@ namespace System.Text.Json.Serialization.Converters internal sealed class VersionConverter : JsonPrimitiveConverter { #if NET - private const int MinimumVersionLength = 3; // 0.0 - - private const int MaximumVersionLength = 43; // 2147483647.2147483647.2147483647.2147483647 + private const int MaximumFormattedVersionLength = 43; // 2147483647.2147483647.2147483647.2147483647 #endif public override Version? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) @@ -100,12 +98,11 @@ public override void Write(Utf8JsonWriter writer, Version? value, JsonSerializer #if NET #if NET8_0_OR_GREATER - Span span = stackalloc byte[MaximumVersionLength]; + Span span = stackalloc byte[MaximumFormattedVersionLength]; #else - Span span = stackalloc char[MaximumVersionLength]; + Span span = stackalloc char[MaximumFormattedVersionLength]; #endif bool formattedSuccessfully = value.TryFormat(span, out int charsWritten); - Debug.Assert(formattedSuccessfully && charsWritten >= MinimumVersionLength); writer.WriteStringValue(span.Slice(0, charsWritten)); #else writer.WriteStringValue(value.ToString()); @@ -123,12 +120,11 @@ internal override void WriteAsPropertyNameCore(Utf8JsonWriter writer, Version va #if NET #if NET8_0_OR_GREATER - Span span = stackalloc byte[MaximumVersionLength]; + Span span = stackalloc byte[MaximumFormattedVersionLength]; #else - Span span = stackalloc char[MaximumVersionLength]; + Span span = stackalloc char[MaximumFormattedVersionLength]; #endif bool formattedSuccessfully = value.TryFormat(span, out int charsWritten); - Debug.Assert(formattedSuccessfully && charsWritten >= MinimumVersionLength); writer.WritePropertyName(span.Slice(0, charsWritten)); #else writer.WritePropertyName(value.ToString()); From 2f7ff2c5432eb230114925dec0b4aa66486f9e10 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 1 Aug 2025 02:16:55 +0000 Subject: [PATCH 12/15] Add .NET 10+ optimization to parse Version directly from UTF8 bytes Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com> --- .../Converters/Value/VersionConverter.cs | 56 +++++++++++++------ 1 file changed, 40 insertions(+), 16 deletions(-) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/VersionConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/VersionConverter.cs index 7e135cf6cb9118..33028c1cc6c232 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/VersionConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/VersionConverter.cs @@ -34,18 +34,13 @@ private static Version ReadCore(ref Utf8JsonReader reader) Debug.Assert(reader.TokenType is JsonTokenType.PropertyName or JsonTokenType.String); #if NET - int bufferLength = reader.ValueLength; - char[]? rentedBuffer = null; - try +#if NET10_0_OR_GREATER + // .NET 10+ optimization: parse directly from UTF8 bytes when the value is in a single span + if (!reader.HasValueSequence && !reader.ValueIsEscaped) { - Span charBuffer = bufferLength <= JsonConstants.StackallocCharThreshold - ? stackalloc char[JsonConstants.StackallocCharThreshold] - : (rentedBuffer = ArrayPool.Shared.Rent(bufferLength)); + ReadOnlySpan utf8Source = reader.ValueSpan; - int bytesWritten = reader.CopyString(charBuffer); - ReadOnlySpan source = charBuffer.Slice(0, bytesWritten); - - if (source.IsEmpty || char.IsWhiteSpace(source[0]) || char.IsWhiteSpace(source[^1])) + if (utf8Source.IsEmpty || utf8Source[0] == (byte)' ' || utf8Source[^1] == (byte)' ') { // Since leading and trailing whitespaces are forbidden throughout System.Text.Json converters // we need to make sure that our input doesn't have them, @@ -54,18 +49,47 @@ private static Version ReadCore(ref Utf8JsonReader reader) ThrowHelper.ThrowFormatException(DataType.Version); } - bool success = Version.TryParse(source, out Version? result); - - if (success) + if (Version.TryParse(utf8Source, out Version? result)) { return result!; } } - finally + else +#endif { - if (rentedBuffer is not null) + int bufferLength = reader.ValueLength; + char[]? rentedBuffer = null; + try + { + Span charBuffer = bufferLength <= JsonConstants.StackallocCharThreshold + ? stackalloc char[JsonConstants.StackallocCharThreshold] + : (rentedBuffer = ArrayPool.Shared.Rent(bufferLength)); + + int bytesWritten = reader.CopyString(charBuffer); + ReadOnlySpan source = charBuffer.Slice(0, bytesWritten); + + if (source.IsEmpty || char.IsWhiteSpace(source[0]) || char.IsWhiteSpace(source[^1])) + { + // Since leading and trailing whitespaces are forbidden throughout System.Text.Json converters + // we need to make sure that our input doesn't have them, + // and if it has - we need to throw, to match behaviour of other converters + // since Version.TryParse allows them and silently parses input to Version + ThrowHelper.ThrowFormatException(DataType.Version); + } + + bool success = Version.TryParse(source, out Version? result); + + if (success) + { + return result!; + } + } + finally { - ArrayPool.Shared.Return(rentedBuffer); + if (rentedBuffer is not null) + { + ArrayPool.Shared.Return(rentedBuffer); + } } } #else From 314f30226dcd7b918f59c911b99e658fd7c5cf61 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 1 Aug 2025 13:56:09 +0000 Subject: [PATCH 13/15] Use char.IsWhiteSpace instead of hardcoded space checks in UTF8 path Co-authored-by: eiriktsarpalis <2813363+eiriktsarpalis@users.noreply.github.com> --- .../Json/Serialization/Converters/Value/VersionConverter.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/VersionConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/VersionConverter.cs index 33028c1cc6c232..d2bc5652971ca3 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/VersionConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/VersionConverter.cs @@ -40,7 +40,9 @@ private static Version ReadCore(ref Utf8JsonReader reader) { ReadOnlySpan utf8Source = reader.ValueSpan; - if (utf8Source.IsEmpty || utf8Source[0] == (byte)' ' || utf8Source[^1] == (byte)' ') + if (utf8Source.IsEmpty || + (utf8Source[0] <= 127 && char.IsWhiteSpace((char)utf8Source[0])) || + (utf8Source[^1] <= 127 && char.IsWhiteSpace((char)utf8Source[^1]))) { // Since leading and trailing whitespaces are forbidden throughout System.Text.Json converters // we need to make sure that our input doesn't have them, From 5032d88f1d202ff19b05974f287338381867e233 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 1 Aug 2025 14:40:52 +0000 Subject: [PATCH 14/15] Use CopyString(Span) to enable UTF8 optimization for all inputs in .NET 10+ Co-authored-by: eiriktsarpalis <2813363+eiriktsarpalis@users.noreply.github.com> --- .../Converters/Value/VersionConverter.cs | 82 +++++++++++-------- 1 file changed, 47 insertions(+), 35 deletions(-) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/VersionConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/VersionConverter.cs index d2bc5652971ca3..b42541a3870e63 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/VersionConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/VersionConverter.cs @@ -35,10 +35,17 @@ private static Version ReadCore(ref Utf8JsonReader reader) #if NET #if NET10_0_OR_GREATER - // .NET 10+ optimization: parse directly from UTF8 bytes when the value is in a single span - if (!reader.HasValueSequence && !reader.ValueIsEscaped) + // .NET 10+ optimization: parse directly from UTF8 bytes for all inputs + int bufferLength = reader.ValueLength; + byte[]? rentedBuffer = null; + try { - ReadOnlySpan utf8Source = reader.ValueSpan; + Span utf8Buffer = bufferLength <= JsonConstants.StackallocByteThreshold + ? stackalloc byte[JsonConstants.StackallocByteThreshold] + : (rentedBuffer = ArrayPool.Shared.Rent(bufferLength)); + + int bytesWritten = reader.CopyString(utf8Buffer); + ReadOnlySpan utf8Source = utf8Buffer.Slice(0, bytesWritten); if (utf8Source.IsEmpty || (utf8Source[0] <= 127 && char.IsWhiteSpace((char)utf8Source[0])) || @@ -56,44 +63,49 @@ private static Version ReadCore(ref Utf8JsonReader reader) return result!; } } - else -#endif + finally { - int bufferLength = reader.ValueLength; - char[]? rentedBuffer = null; - try + if (rentedBuffer is not null) + { + ArrayPool.Shared.Return(rentedBuffer); + } + } +#else + int bufferLength = reader.ValueLength; + char[]? rentedBuffer = null; + try + { + Span charBuffer = bufferLength <= JsonConstants.StackallocCharThreshold + ? stackalloc char[JsonConstants.StackallocCharThreshold] + : (rentedBuffer = ArrayPool.Shared.Rent(bufferLength)); + + int bytesWritten = reader.CopyString(charBuffer); + ReadOnlySpan source = charBuffer.Slice(0, bytesWritten); + + if (source.IsEmpty || char.IsWhiteSpace(source[0]) || char.IsWhiteSpace(source[^1])) + { + // Since leading and trailing whitespaces are forbidden throughout System.Text.Json converters + // we need to make sure that our input doesn't have them, + // and if it has - we need to throw, to match behaviour of other converters + // since Version.TryParse allows them and silently parses input to Version + ThrowHelper.ThrowFormatException(DataType.Version); + } + + bool success = Version.TryParse(source, out Version? result); + + if (success) { - Span charBuffer = bufferLength <= JsonConstants.StackallocCharThreshold - ? stackalloc char[JsonConstants.StackallocCharThreshold] - : (rentedBuffer = ArrayPool.Shared.Rent(bufferLength)); - - int bytesWritten = reader.CopyString(charBuffer); - ReadOnlySpan source = charBuffer.Slice(0, bytesWritten); - - if (source.IsEmpty || char.IsWhiteSpace(source[0]) || char.IsWhiteSpace(source[^1])) - { - // Since leading and trailing whitespaces are forbidden throughout System.Text.Json converters - // we need to make sure that our input doesn't have them, - // and if it has - we need to throw, to match behaviour of other converters - // since Version.TryParse allows them and silently parses input to Version - ThrowHelper.ThrowFormatException(DataType.Version); - } - - bool success = Version.TryParse(source, out Version? result); - - if (success) - { - return result!; - } + return result!; } - finally + } + finally + { + if (rentedBuffer is not null) { - if (rentedBuffer is not null) - { - ArrayPool.Shared.Return(rentedBuffer); - } + ArrayPool.Shared.Return(rentedBuffer); } } +#endif #else string? versionString = reader.GetString(); if (string.IsNullOrEmpty(versionString) || char.IsWhiteSpace(versionString[0]) || char.IsWhiteSpace(versionString[versionString.Length - 1])) From 1cfc81adb4563a73c2319d4a685f3bbb288bf4bb Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 1 Aug 2025 15:27:13 +0000 Subject: [PATCH 15/15] Remove .NET 10+ UTF8 optimization from VersionConverter to simplify whitespace validation Co-authored-by: eiriktsarpalis <2813363+eiriktsarpalis@users.noreply.github.com> --- .../Converters/Value/VersionConverter.cs | 38 ------------------- 1 file changed, 38 deletions(-) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/VersionConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/VersionConverter.cs index b42541a3870e63..7e135cf6cb9118 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/VersionConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/VersionConverter.cs @@ -34,43 +34,6 @@ private static Version ReadCore(ref Utf8JsonReader reader) Debug.Assert(reader.TokenType is JsonTokenType.PropertyName or JsonTokenType.String); #if NET -#if NET10_0_OR_GREATER - // .NET 10+ optimization: parse directly from UTF8 bytes for all inputs - int bufferLength = reader.ValueLength; - byte[]? rentedBuffer = null; - try - { - Span utf8Buffer = bufferLength <= JsonConstants.StackallocByteThreshold - ? stackalloc byte[JsonConstants.StackallocByteThreshold] - : (rentedBuffer = ArrayPool.Shared.Rent(bufferLength)); - - int bytesWritten = reader.CopyString(utf8Buffer); - ReadOnlySpan utf8Source = utf8Buffer.Slice(0, bytesWritten); - - if (utf8Source.IsEmpty || - (utf8Source[0] <= 127 && char.IsWhiteSpace((char)utf8Source[0])) || - (utf8Source[^1] <= 127 && char.IsWhiteSpace((char)utf8Source[^1]))) - { - // Since leading and trailing whitespaces are forbidden throughout System.Text.Json converters - // we need to make sure that our input doesn't have them, - // and if it has - we need to throw, to match behaviour of other converters - // since Version.TryParse allows them and silently parses input to Version - ThrowHelper.ThrowFormatException(DataType.Version); - } - - if (Version.TryParse(utf8Source, out Version? result)) - { - return result!; - } - } - finally - { - if (rentedBuffer is not null) - { - ArrayPool.Shared.Return(rentedBuffer); - } - } -#else int bufferLength = reader.ValueLength; char[]? rentedBuffer = null; try @@ -105,7 +68,6 @@ private static Version ReadCore(ref Utf8JsonReader reader) ArrayPool.Shared.Return(rentedBuffer); } } -#endif #else string? versionString = reader.GetString(); if (string.IsNullOrEmpty(versionString) || char.IsWhiteSpace(versionString[0]) || char.IsWhiteSpace(versionString[versionString.Length - 1]))