diff --git a/src/libraries/System.Text.RegularExpressions/gen/RegexGenerator.Emitter.cs b/src/libraries/System.Text.RegularExpressions/gen/RegexGenerator.Emitter.cs index 053cbcf62430e..2c72270daa358 100644 --- a/src/libraries/System.Text.RegularExpressions/gen/RegexGenerator.Emitter.cs +++ b/src/libraries/System.Text.RegularExpressions/gen/RegexGenerator.Emitter.cs @@ -535,6 +535,17 @@ bool EmitAnchors() Goto(NoStartingPositionFound); } writer.WriteLine("pos = newlinePos + pos + 1;"); + + // We've updated the position. Make sure there's still enough room in the input for a possible match. + using (EmitBlock(writer, minRequiredLength switch + { + 0 => "if (pos > inputSpan.Length)", + 1 => "if (pos >= inputSpan.Length)", + _ => $"if (pos > inputSpan.Length - {minRequiredLength})" + })) + { + Goto(NoStartingPositionFound); + } } writer.WriteLine(); break; diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCompiler.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCompiler.cs index 765be58207950..670b76f8dd1b4 100644 --- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCompiler.cs +++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCompiler.cs @@ -622,6 +622,18 @@ bool GenerateAnchors() Ldc(1); Add(); Stloc(pos); + + // We've updated the position. Make sure there's still enough room in the input for a possible match. + // if (pos > inputSpan.Length - minRequiredLength) returnFalse; + Ldloca(inputSpan); + Call(s_spanGetLengthMethod); + if (minRequiredLength != 0) + { + Ldc(minRequiredLength); + Sub(); + } + Ldloc(pos); + BltFar(returnFalse); } MarkLabel(label); diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexFindOptimizations.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexFindOptimizations.cs index fc1b1adb73cf4..fafa72042dede 100644 --- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexFindOptimizations.cs +++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexFindOptimizations.cs @@ -281,7 +281,13 @@ public bool TryFindNextStartingPosition(ReadOnlySpan textSpan, ref int pos return false; } + // We've updated the position. Make sure there's still enough room in the input for a possible match. pos = newline + 1 + pos; + if (pos > textSpan.Length - MinRequiredLength) + { + pos = textSpan.Length; + return false; + } } } diff --git a/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.MultipleMatches.Tests.cs b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.MultipleMatches.Tests.cs index 34f60c672e110..e3884f15a2dcc 100644 --- a/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.MultipleMatches.Tests.cs +++ b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.MultipleMatches.Tests.cs @@ -176,7 +176,7 @@ public static IEnumerable Matches_TestData() } }; - // Using ^ with multiline + // Using ^ and $ with multiline yield return new object[] { engine, @@ -244,6 +244,38 @@ public static IEnumerable Matches_TestData() } }; + yield return new object[] + { + engine, + @"^[^a]a", "bar\n", RegexOptions.Multiline, + new[] + { + new CaptureData("ba", 0, 2) + } + }; + + yield return new object[] + { + engine, + @"^[^a]a", "car\nbar\n", RegexOptions.Multiline, + new[] + { + new CaptureData("ca", 0, 2), + new CaptureData("ba", 4, 2) + } + }; + + yield return new object[] + { + engine, + @"[0-9]cat$", "1cat\n2cat", RegexOptions.Multiline, + new[] + { + new CaptureData("1cat", 0, 4), + new CaptureData("2cat", 5, 4) + } + }; + if (!PlatformDetection.IsNetFramework) { // .NET Framework missing fix in https://github.com/dotnet/runtime/pull/1075