dotnet / dotnet/runtime

RegexOptions.Compiled Backtracking Regression on .NET 10 from .NET 8

Open
#133,429 1 comment 0 reactions 0 assignees View on GitHub
area-System.Text.RegularExpressions regression-from-last-release
Dominant language
C#
Stars
18.3k
Forks
5.6k
PR merge metrics
PR metrics pending

Description

### Description

A backtracking-prone pattern completes instantly on .NET 8 (both interpreted and compiled) hangs indefinitely on .NET 10 with `RegexOptions.Compiled`. I am able to reproduce on version 10.0.11.

### Reproduction Steps

`Program.cs` in a project targeting `net8.0;net10.0`:

```csharp
using System.Text.RegularExpressions;

// Optional numeric group, then
// Bounded lazy filler of tokens, then
// Numeric group, then
// Keyword alternation with a negative lookahead
const string pattern = @"\b(scan\w*|scanned|sc|print\w*|printed)\b\s+(?:(\d+(?:,\d{3})*[km]?)\s+)?(?:[A-Za-z0-9.-]+\s+){0,2}?(\d+(?:\.\d+)?)\s*(?:(a|b)\b|(reads?|writes?)\b(?!\s+cache))";

// Two non-matching lines
const string input = "scanned 12 foo 34 567 8.90 read 1.11\nprinted 12 foo 34 567 8.90 write 2.22";

var interpreted = new Regex(pattern, RegexOptions.IgnoreCase);
var compiled = new Regex(pattern, RegexOptions.IgnoreCase | RegexOptions.Compiled);

Console.WriteLine($".NET {Environment.Version}");
Measure("interpreted", interpreted);
Measure("compiled", compiled);

void Measure(string name, Regex regex)
{
int count = 0;
var sw = System.Diagnostics.Stopwatch.StartNew();
var task = Task.Run(() =>
{
foreach (Match _ in regex.Matches(input))
{
count ++;
}
}
bool finished = task.Wait(TimeSpan.FromSeconds(10));
Console.WriteLine(finished
? $" {name,-11}: completed in {sw.ElapsedMilliseconds} ms ({count} matches)
: $" {name,-11}: DID NOT COMPLETE within 10s");
}
```

Run:
```
dotnet run -c Release -f net8.0
dotnet run -c Release -f net10.0
```

### Expected behavior

The compiled engine terminates quickly, matching the interpreted engine and .NET 8.

```
.NET 8.0.27
interpreted: completed in 1 ms (0 matches)
compiled : completed in 11 ms (0 matches)
```

### Actual behavior

On .NET 10 the compiled engine does not terminate, while the interpreted engine is fine.

```
.NET 10.0.11
interpreted: completed in 2 ms (0 matches)
compiled : DID NOT COMPLETE within 10s
```

### Regression?

Yes. Works on .NET 8.0.27 (both engines). Fails on .NET 10.0.8 and 10.0.11 (compiled only).

### Known Workarounds

Drop `RegexOptions.Compiled` (use the interpreted engine), or set a `matchTimeout` so the runaway throws `RegexMatchTimeoutException` instead of hanging.

### Configuration

* Reproduced on Microsoft.NETCore.App 10.0.8 and 10.0.11 (latest 10.0.x, 2026-08-11), Windows x64
* .NET SDK 10.0.300
* Not present on .NET 8.0.27 (baseline)

### Other information

_No response_

Contributor guide

Open the contributing guide

Research direction

Run the supplied Program.cs reproduction in Release for net8.0 and net10.0, comparing interpreted and RegexOptions.Compiled execution. Trace the compiled regex path from the reported behavior and use the existing regex test area if locating it in the runtime is necessary. Done means the net10.0 compiled engine terminates quickly and reports zero matches, without requiring a timeout.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp
Domain
performance
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.