From 1dcb1edd36775bf1d5e336e3de8e563b2bb1034e Mon Sep 17 00:00:00 2001 From: quick_fox Date: Sun, 27 Sep 2026 09:17:27 +0800 Subject: [PATCH 1/4] Add custom numeric format regression tests --- .../tests/System.Runtime.Tests/System/Int32Tests.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int32Tests.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int32Tests.cs index a14003e1f90bed..36f06fe678e8ee 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int32Tests.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int32Tests.cs @@ -131,6 +131,8 @@ public static IEnumerable ToString_TestData() } NumberFormatInfo invariantFormat = NumberFormatInfo.InvariantInfo; + yield return new object[] { 7, "A1111111111-0", invariantFormat, "A1111111111-7" }; + yield return new object[] { 7, "A1234567890Z", invariantFormat, "A1234567897Z" }; yield return new object[] { 32, "C100", invariantFormat, "\u00A432.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" }; yield return new object[] { 32, "P100", invariantFormat, "3,200.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 %" }; yield return new object[] { 32, "D100", invariantFormat, "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000032" }; @@ -197,6 +199,7 @@ public static void ToString_InvalidFormat_ThrowsFormatException() int i = 123; Assert.Throws(() => i.ToString("Y")); // Invalid format Assert.Throws(() => i.ToString("Y", null)); // Invalid format + Assert.Throws(() => i.ToString("D1000000000")); // Precision too large } public static IEnumerable Parse_Valid_TestData() From d744c7713d2b023baac93dd1cb177a150e560df4 Mon Sep 17 00:00:00 2001 From: quick_fox Date: Sun, 27 Sep 2026 09:17:35 +0800 Subject: [PATCH 2/4] Fix custom numeric format precision parsing --- .../src/System/Number.Formatting.Common.cs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/libraries/Common/src/System/Number.Formatting.Common.cs b/src/libraries/Common/src/System/Number.Formatting.Common.cs index 3732355789e185..6c6babe2be0247 100644 --- a/src/libraries/Common/src/System/Number.Formatting.Common.cs +++ b/src/libraries/Common/src/System/Number.Formatting.Common.cs @@ -147,20 +147,29 @@ internal static char ParseFormatSpecifier(ReadOnlySpan format, out int dig // digits. Further, for compat, we need to stop when we hit a null char. int n = 0; int i = 1; + bool precisionTooLarge = false; while ((uint)i < (uint)format.Length && char.IsAsciiDigit(format[i])) { - // Check if we are about to overflow past our limit of 9 digits if (n >= 100_000_000) { - ThrowHelper.ThrowFormatException_BadFormatSpecifier(); + precisionTooLarge = true; + } + else + { + n = (n * 10) + format[i] - '0'; } - n = (n * 10) + format[i++] - '0'; + i++; } // If we're at the end of the digits rather than having stopped because we hit something - // other than a digit or overflowed, return the standard format info. + // other than a digit, this is a standard format. if ((uint)i >= (uint)format.Length || format[i] == '\0') { + if (precisionTooLarge) + { + ThrowHelper.ThrowFormatException_BadFormatSpecifier(); + } + digits = n; return c; } From e6ff407eea58e8072575a7a2ccb5e6b4b121bdb0 Mon Sep 17 00:00:00 2001 From: quick_fox Date: Sun, 27 Sep 2026 09:17:45 +0800 Subject: [PATCH 3/4] Cover standard-shaped numeric format case --- .../tests/System.Runtime.Tests/System/Int32Tests.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int32Tests.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int32Tests.cs index 36f06fe678e8ee..e45c343700bb4a 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int32Tests.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int32Tests.cs @@ -200,6 +200,7 @@ public static void ToString_InvalidFormat_ThrowsFormatException() Assert.Throws(() => i.ToString("Y")); // Invalid format Assert.Throws(() => i.ToString("Y", null)); // Invalid format Assert.Throws(() => i.ToString("D1000000000")); // Precision too large + Assert.Throws(() => i.ToString("A1234567890")); // Standard-shaped format } public static IEnumerable Parse_Valid_TestData() From 29c90ff280ef15f8d122035993d6829fc9b0f147 Mon Sep 17 00:00:00 2001 From: quick_fox Date: Sun, 27 Sep 2026 09:17:53 +0800 Subject: [PATCH 4/4] Add BigInteger format regression coverage --- .../tests/BigInteger/BigIntegerToStringTests.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libraries/System.Runtime.Numerics/tests/BigInteger/BigIntegerToStringTests.cs b/src/libraries/System.Runtime.Numerics/tests/BigInteger/BigIntegerToStringTests.cs index f5b466083ce9b6..e2e6fea5a162e0 100644 --- a/src/libraries/System.Runtime.Numerics/tests/BigInteger/BigIntegerToStringTests.cs +++ b/src/libraries/System.Runtime.Numerics/tests/BigInteger/BigIntegerToStringTests.cs @@ -464,6 +464,8 @@ public static void RunCustomFormatLiterals() RunCustomFormatToStringTests(s_random, "0\"\\\"", CultureInfo.CurrentCulture.NumberFormat.NegativeSign, 1, ExtraFormatter(ZeroFormatter, "\\")); RunCustomFormatToStringTests(s_random, "#\',\'%", CultureInfo.CurrentCulture.NumberFormat.NegativeSign, 0, ExtraFormatter(PercentSymbolFormatter, ",", CultureInfo.CurrentCulture.NumberFormat.PercentSymbol.Length)); RunCustomFormatToStringTests(s_random, "000\",\".000", CultureInfo.CurrentCulture.NumberFormat.NegativeSign, 3, ExtraFormatter(DecimalPointFormatter, ",", CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator.Length + 3)); + VerifyToString("7", "A1111111111-0", "A1111111111-7"); + VerifyToString("7", "A1234567890Z", "A1234567897Z"); } [Fact]