Skip to content

Fix StackOverflow crash on cyclic local initializers (MA0091/MA0092/MA0093) - #1341

Merged
meziantou merged 1 commit into
mainfrom
feature/meziantou-analyzer-1323-9027ed
Aug 26, 2026
Merged

Fix StackOverflow crash on cyclic local initializers (MA0091/MA0092/MA0093)#1341
meziantou merged 1 commit into
mainfrom
feature/meziantou-analyzer-1323-9027ed

Conversation

@meziantou

Copy link
Copy Markdown
Owner

Fixes #1323

What changed

EventsShouldHaveProperArgumentsAnalyzer.EventReferenceVisitor.FindFromLocalSymbol resolved a local's initializer and, when that initializer bound to another ILocalSymbol, called itself — with no visited set. Two locals whose initializers reference each other made the walk recurse until the process died:

class C
{
    void M()
    {
        System.EventHandler a = b;
        System.EventHandler b = a;
        a.Invoke(this, System.EventArgs.Empty);
    }
}

FindFromLocalSymbol now tracks the visited locals in a HashSet<ISymbol> (with SymbolEqualityComparer.Default) held by the visitor instance and bails on re-entry.

The two hardcoded CancellationToken.None arguments are also gone: the visitor now takes the real context.CancellationToken through a primary constructor, so the token parameter disappears from the recursive method's signature. With a cycle present, cancellation was the only thing that could have stopped the walk.

Why it matters

A StackOverflowException cannot be caught by Roslyn's analyzer host, so this was not a recoverable AD0001 — the whole process died (VBCSCompiler, Visual Studio, Rider, OmniSharp). MA0091, MA0092 and MA0093 are all enabled by default at Warning.

The source that triggers it does not compile (CS0841, use before declaration), which is exactly the state of a file while it is being typed — and IDE live analysis runs continuously on erroneous compilations.

Test infrastructure

ProjectBuilder.IsValidCode, set by WithNoCompilation(), was declared but never read: GetSortedDiagnostics hardcoded compileSolution: true, so no analyzer test could use non-compiling source (Assert.Fail("The code doesn't compile.")). It now passes IsValidCode, which is what makes the regression tests possible. No existing test used WithNoCompilation(), so nothing else changes behavior.

Tests

Two regression tests: the mutual a = b; b = a; cycle from the issue, and a self-referencing EventHandler a = a;.

I confirmed the new test actually reproduces the bug — with the visited-set guard temporarily removed, the run died exactly as reported in the issue (Test run summary: Zero tests ran, exit code 7, createdump). Guard restored, it passes.

  • 12/12 tests in EventsShouldHaveProperArgumentsAnalyzerTests pass on all five Roslyn versions (4.8, 4.14, 5.0, 5.6, 5.9)
  • Full suite on the default version: 3776/3776 passed
  • dotnet run --project src/DocumentationGenerator produced no markdown changes

EventReferenceVisitor.FindFromLocalSymbol resolved a local's initializer and
recursed when it bound to another local, with no visited set. Two locals whose
initializers reference each other made the walk recurse until the process died.
A StackOverflowException cannot be caught by the analyzer host, so this killed
VBCSCompiler, Visual Studio, Rider or OmniSharp instead of being reported as
AD0001. The source that triggers it does not compile (CS0841), which is exactly
the state of a file while it is being typed, and IDE live analysis runs
continuously on erroneous compilations.

Track the visited locals in a HashSet<ISymbol> and bail on re-entry. While
there, use the real CancellationToken instead of CancellationToken.None: with a
cycle present, cancellation was the only thing that could have stopped the walk.

ProjectBuilder.IsValidCode, set by WithNoCompilation(), was declared but never
read: GetSortedDiagnostics hardcoded compileSolution: true, so no analyzer test
could use non-compiling source. Pass IsValidCode so the regression tests can
cover it. No existing test used WithNoCompilation().
@meziantou
meziantou enabled auto-merge (squash) August 26, 2026 18:37
@meziantou
meziantou merged commit c6054ab into main Aug 26, 2026
13 checks passed
@meziantou
meziantou deleted the feature/meziantou-analyzer-1323-9027ed branch August 26, 2026 18:38
This was referenced Aug 26, 2026
This was referenced Aug 31, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Analyzer crashes the compiler process with a StackOverflow on cyclic local initializers (MA0091/MA0092/MA0093)

1 participant