Skip to content

Commit 43e729d

Browse files
Copilotstephentoub
andcommitted
Fix TransferCapture to prevent negative-length captures in balancing groups
When a balancing group captures content that precedes the balanced group's position, the "innermost interval" logic could create captures with negative lengths. These negative-length captures were incorrectly removed by TidyBalancing, causing inconsistency between IsMatched() during matching and Group.Success after tidying. The fix ensures that when end < start after the innermost interval calculation, we set end = start to create a zero-length capture instead, which correctly survives TidyBalancing. Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com>
1 parent 59be2e6 commit 43e729d

File tree

2 files changed

+10
-34
lines changed

2 files changed

+10
-34
lines changed

src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Match.cs

Lines changed: 4 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -233,40 +233,10 @@ internal void BalanceMatch(int cap)
233233
internal bool IsMatched(int cap)
234234
{
235235
int[] matchcount = _matchcount;
236-
if ((uint)cap >= (uint)matchcount.Length || matchcount[cap] == 0)
237-
{
238-
return false;
239-
}
240-
241-
// If not balancing, the simple check suffices
242-
if (!_balancing)
243-
{
244-
return _matches[cap][matchcount[cap] * 2 - 1] != (-3 + 1);
245-
}
246-
247-
// When balancing is involved, we need to check if there are any real (non-negative) captures
248-
// that would remain after TidyBalancing compacts the captures.
249-
// TidyBalancing removes negative (balanced) captures, so we need to count positive ones.
250-
int[] matcharray = _matches[cap];
251-
int limit = matchcount[cap] * 2;
252-
int realCaptureCount = 0;
253-
254-
for (int i = 0; i < limit; i += 2)
255-
{
256-
// Check if this is a real capture (start index is non-negative)
257-
if (matcharray[i] >= 0)
258-
{
259-
realCaptureCount++;
260-
}
261-
else
262-
{
263-
// This is a balancing marker (negative index)
264-
// Balancing markers effectively "remove" a previous capture
265-
realCaptureCount--;
266-
}
267-
}
268-
269-
return realCaptureCount > 0;
236+
return
237+
(uint)cap < (uint)matchcount.Length &&
238+
matchcount[cap] > 0 &&
239+
_matches[cap][matchcount[cap] * 2 - 1] != (-3 + 1);
270240
}
271241

272242
/// <summary>

src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexRunner.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -573,6 +573,12 @@ protected void TransferCapture(int capnum, int uncapnum, int start, int end)
573573
else if (end <= start2)
574574
{
575575
start = start2;
576+
// Ensure we don't create a capture with negative length
577+
// When the balancing capture precedes the balanced group, end might be less than the new start
578+
if (end < start)
579+
{
580+
end = start;
581+
}
576582
}
577583
else
578584
{

0 commit comments

Comments
 (0)