Skip to content

Commit 27214a0

Browse files
authored
Fix negative lookaround stack handling (#99424)
* Fix negative lookaround stack handling If the body of negative lookaround inside of a loop and containing a capture ends up successfully matching (which means the negative lookaround fails to match), it ends up erroneously leaving a position on the backtracking stack. This fix ensures that state is popped. * Add innerloop test
1 parent 28978b0 commit 27214a0

File tree

4 files changed

+16
-1
lines changed

4 files changed

+16
-1
lines changed

Diff for: src/libraries/System.Text.RegularExpressions/gen/RegexGenerator.Emitter.cs

+6
Original file line numberDiff line numberDiff line change
@@ -2706,6 +2706,12 @@ void EmitNegativeLookaroundAssertion(RegexNode node)
27062706
// If the generated code ends up here, it matched the lookaround, which actually
27072707
// means failure for a _negative_ lookaround, so we need to jump to the original done.
27082708
writer.WriteLine();
2709+
if (hasCaptures && isInLoop)
2710+
{
2711+
// Pop the crawl position from the stack.
2712+
writer.WriteLine("stackpos--;");
2713+
EmitStackCookieValidate(stackCookie);
2714+
}
27092715
Goto(originalDoneLabel);
27102716
writer.WriteLine();
27112717

Diff for: src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCompiler.cs

+9
Original file line numberDiff line numberDiff line change
@@ -2640,6 +2640,15 @@ void EmitNegativeLookaroundAssertion(RegexNode node)
26402640
// If the generated code ends up here, it matched the lookaround, which actually
26412641
// means failure for a _negative_ lookaround, so we need to jump to the original done.
26422642
// goto originalDoneLabel;
2643+
if (capturePos is not null && isInLoop)
2644+
{
2645+
// Pop the crawl position from the stack.
2646+
// stackpos--;
2647+
Ldloc(stackpos);
2648+
Ldc(1);
2649+
Sub();
2650+
Stloc(stackpos);
2651+
}
26432652
BrFar(originalDoneLabel);
26442653

26452654
// Failures (success for a negative lookaround) jump here.

Diff for: src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.KnownPattern.Tests.cs

-1
Original file line numberDiff line numberDiff line change
@@ -1409,7 +1409,6 @@ public static IEnumerable<object[]> RecreationalRegex_Rectangle_MemberData()
14091409
}
14101410
}
14111411

1412-
[ActiveIssue("https://github.com/dotnet/runtime/issues/98962")]
14131412
[Theory]
14141413
[MemberData(nameof(RecreationalRegex_Rectangle_MemberData))]
14151414
[OuterLoop("May take several seconds")]

Diff for: src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.Match.Tests.cs

+1
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ public static IEnumerable<object[]> Match_MemberData()
9292
yield return (@"(?:(?!(b)b)\1a)+", "babababa", RegexOptions.None, 0, 8, false, string.Empty);
9393
yield return (@"(?:(?!(b)b)\1a)*", "babababa", RegexOptions.None, 0, 8, true, string.Empty);
9494
yield return (@"(.*?)a(?!(a+)b\2c)\2(.*)", "baaabaac", RegexOptions.None, 0, 8, false, string.Empty);
95+
yield return (@"(?!(abc))+\w\w\w", "abcdef", RegexOptions.None, 0, 6, true, "bcd");
9596

9697
// Zero-width positive lookbehind assertion
9798
yield return (@"(\w){6}(?<=XXX)def", "abcXXXdef", RegexOptions.None, 0, 9, true, "abcXXXdef");

0 commit comments

Comments
 (0)