Summary
Fix cross-invocation static-state leaks in the engine. These are latent bugs today — they manifest whenever BuildManager.Execute runs twice in one process (test harnesses, the dotnet fallout global tool, future in-process/IDE scenarios).
Findings (file:line)
BuildManager.cs:42 — ToolOptions.Created += … subscribed every run, never removed.
BuildManager.cs:41 / :69 — Console.CancelKeyPress += and CancellationHandler += Finish accumulate; s_cancellationHandlers (:20) is never cleared.
Logging.cs:214-233 — InMemorySink.Instance._logEvents accumulates; Dispose() (which clears) is never called → run 2 reports run 1's errors/warnings.
VerbosityMappingAttribute.cs:34-46 — Mappings is a LookupTable (dict-of-lists) appended to on every OnBuildInitialized with no dedup → duplicate keys pile up.
Scope
- Make event subscriptions idempotent (subscribe-once, or unsubscribe in
finally).
- Clear/reset
InMemorySink per run (or call Dispose).
- Dedup or reset
VerbosityMapping.Mappings per run.
Acceptance criteria
- A test that calls
Execute twice in one process shows: no duplicated handlers firing, no carried-over log events, no duplicate verbosity mappings.
- No public API change.
Notes
- Non-breaking. No dependencies — do this first; it's shippable on its own.
- Size: S.
Summary
Fix cross-invocation static-state leaks in the engine. These are latent bugs today — they manifest whenever
BuildManager.Executeruns twice in one process (test harnesses, thedotnet falloutglobal tool, future in-process/IDE scenarios).Findings (file:line)
BuildManager.cs:42—ToolOptions.Created += …subscribed every run, never removed.BuildManager.cs:41/:69—Console.CancelKeyPress +=andCancellationHandler += Finishaccumulate;s_cancellationHandlers(:20) is never cleared.Logging.cs:214-233—InMemorySink.Instance._logEventsaccumulates;Dispose()(which clears) is never called → run 2 reports run 1's errors/warnings.VerbosityMappingAttribute.cs:34-46—Mappingsis aLookupTable(dict-of-lists) appended to on everyOnBuildInitializedwith no dedup → duplicate keys pile up.Scope
finally).InMemorySinkper run (or callDispose).VerbosityMapping.Mappingsper run.Acceptance criteria
Executetwice in one process shows: no duplicated handlers firing, no carried-over log events, no duplicate verbosity mappings.Notes