Skip to content

StackOverflowException in WeightedMatch.MatchRecursive with deeply nested/ambiguous diagnostics #1253

Description

@ana1250

Describe the bug

Analyzer tests using Microsoft.CodeAnalysis.Testing can hit a StackOverflowException inside WeightedMatch.MatchRecursive when there are many ambiguous/identical diagnostics to match.

This seems to be related to the recursive matching algorithm exploring a large number of possible pairings between expected and actual diagnostics, leading to stack exhaustion.

Repro

A minimal repro is to generate many diagnostics with the same ID and similar spans. This can be triggered by deeply nesting diagnostic markup:

static string CS0535(string interfaceName, int memberCount)
{
    var result = interfaceName;

    while (memberCount-- > 0)
        result = $"{{|CS0535:{result}|}}";

    return result;
}

Used in a test source string like this:

public class MyTestCase : {{CS0535("ITestCase", 19)}} { }

Running this through the standard analyzer verifier (e.g., VerifyAnalyzerAsync) causes a StackOverflowException during the diagnostic matching phase in the testing infrastructure.

Expected behavior

The test framework should either:
Handle large/ambiguous diagnostic sets without unbounded recursion.
Fail gracefully with a clear exception/message indicating that the diagnostic matching is too ambiguous to resolve.

Actual behavior

A StackOverflowException is thrown from Microsoft.CodeAnalysis.Testing.WeightedMatch.MatchRecursive.

Environment

.NET: 8.0
Microsoft.CodeAnalysis.Testing: 1.1.3
OS: macOS (observed in CI), but likely dependent on thread stack limits.

Notes:
The issue is easier to reproduce on macOS CI runners, likely due to lower default thread stack limits.
The same tests may pass on Windows/Linux but still exhibit high recursion depth.
Possible direction

It may help to:

Limit recursion depth or branching in WeightedMatch.
Introduce heuristics for identical diagnostics (same ID/span).
Provide an option to avoid exhaustive matching in favor of deterministic pairing.

CI logs

Example failure from macOS CI:
https://github.com/xunit/xunit.analyzers/actions/runs/24482992296/job/71551592115

Let me know if you'd like a reduced standalone repro project!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions