In 18.11.0 a test host that has passed every test aborts while the session is finishing.
SharedBufferReconciler.Reconcile waits on a cross-process mutex. When a concurrently running host exits while still owning that mutex, the next waiter is handed an AbandonedMutexException, which is not handled. The process dies with SIGABRT (OS exit 134) and the platform reports exit code 7.
Unhandled exception. System.Threading.AbandonedMutexException: The wait completed due to an abandoned mutex.
at System.Threading.WaitHandle.WaitOneNoCheck(Int32 millisecondsTimeout, Boolean useTrivialWaits, Object associatedObject, WaitHandleWaitSourceMap waitSource)
at Microsoft.CodeCoverage.Core.Threading.Mutex.WaitOne(TimeSpan timeout)
at Microsoft.CodeCoverage.Instrumentation.SharedBufferReconciler.Reconcile(IAppDomainDataReader appDomainDataReader, IMutexFactory mutexFactory, Int32 mutexTimeoutMs)
at Microsoft.CodeCoverage.Instrumentation.SharedBufferReconciler.Reconcile(IAppDomainDataReader appDomainDataReader, IMutexFactory mutexFactory)
at Microsoft.Testing.Extensions.CodeCoverage.TestingPlatformCoverageDynamicTestSessionLifetimeHandler.OnTestSessionFinishingAsync(ITestSessionContext testSessionContext)
at Microsoft.Testing.Platform.Hosts.CommonHost.NotifyTestSessionEndAsync(ITestSessionContext testSessionContext, BaseMessageBus baseMessageBus, ServiceProvider serviceProvider, IPlatformOpenTelemetryService otelService)
Repro
Several test assemblies must run concurrently; a single test project does not reproduce it (25 consecutive runs of one project were clean).
dotnet test --solution <solution> -c Release --coverage --coverage-output-format cobertura
The run reports failed: 0 for every test, then one arbitrary assembly is marked failed and the run exits 7. Which assembly loses the race varies between runs, so it may take a few attempts.
Versions
|
result |
| 18.11.0 (latest published) |
reproduces |
| 18.10.0 |
does not reproduce |
Microsoft.Testing.Platform.MSBuild 2.4.0, TUnit, net8.0/net9.0/net10.0/net11.0 hosts. Reproduced on both Linux x64 and macOS arm64.
Secondary impact: coverage is silently under-reported
The aborting host never reconciles its buffers, so its data is dropped rather than merged. Union line coverage across the same commit, only the collector version differing:
| collector |
exit |
union line coverage |
| 18.10.0 |
0 |
12820/13537 = 94.70% |
| 18.11.0 |
7 |
12097/13537 = 89.36% |
A consumer who ignores the exit code still gets a number that is quietly ~5 points low.
Links
In 18.11.0 a test host that has passed every test aborts while the session is finishing.
SharedBufferReconciler.Reconcilewaits on a cross-process mutex. When a concurrently running host exits while still owning that mutex, the next waiter is handed anAbandonedMutexException, which is not handled. The process dies with SIGABRT (OS exit 134) and the platform reports exit code 7.Repro
Several test assemblies must run concurrently; a single test project does not reproduce it (25 consecutive runs of one project were clean).
The run reports
failed: 0for every test, then one arbitrary assembly is marked failed and the run exits 7. Which assembly loses the race varies between runs, so it may take a few attempts.Versions
Microsoft.Testing.Platform.MSBuild2.4.0, TUnit, net8.0/net9.0/net10.0/net11.0 hosts. Reproduced on both Linux x64 and macOS arm64.Secondary impact: coverage is silently under-reported
The aborting host never reconciles its buffers, so its data is dropped rather than merged. Union line coverage across the same commit, only the collector version differing:
A consumer who ignores the exit code still gets a number that is quietly ~5 points low.
Links