dotnet / roslyn

The Roslyn .NET compiler provides C# and Visual Basic languages with rich code analysis APIs.
https://docs.microsoft.com/dotnet/csharp/roslyn-sdk/
MIT License
18.88k stars 4.01k forks source link

Workspace disposal during MEF shutdown may try to create more stuff and throw exceptions #56177

Open jasonmalinowski opened 3 years ago

jasonmalinowski commented 3 years ago

VisualStudioWorkspace is MEF exported, which means it's Dispose() is called during the MEF container shutdown. In dispose, we run this:

https://github.com/dotnet/roslyn/blob/34a521565b359ab3b396577b1535211fdc8733b7/src/Workspaces/Core/Portable/Workspace/Workspace.cs#L372

If we've never raised an event in the workspace, because the workspace never got file changes, then this tries to create the implementation of IWorkspaceEventListenerService, which will throw because the MEF container is already being disposed -- it appears VS MEF doesn't allow new parts to be created once disposal has begun (which sounds pretty reasonable to me.) As a result we throw exceptions with the stack below.

A possible repro here is to open our Tools > Options and then close VS. It appears we create the VisualStudioWorkspace somewhere but since you never open a project it never was changed.

This exception was originally thrown at this call stack:
Microsoft.Verify.NotDisposed(Microsoft.IDisposableObservable, string)
Microsoft.VisualStudio.Composition.ExportProvider.CreateExport.AnonymousMethod__0()
Microsoft.VisualStudio.Composition.ExportProvider.GetExports.AnonymousMethod__5()
System.Lazy<T>.CreateValue()
System.Lazy<T>.LazyInitValue()
Microsoft.VisualStudio.Composition.ExportProvider.GetExports.AnonymousMethod__2()
System.Lazy<T>.CreateValue()
System.Lazy<T>.LazyInitValue()
Microsoft.CodeAnalysis.Host.Mef.MefWorkspaceServices..ctor.AnonymousMethod__1() in MefWorkspaceServices.cs
mscorlib.dll!System.Lazy<Microsoft.CodeAnalysis.Host.Mef.IWorkspaceServiceFactory>.LazyInitValue()  Unknown
Microsoft.CodeAnalysis.Workspaces.dll!Microsoft.CodeAnalysis.Host.Mef.MefWorkspaceServices..ctor.AnonymousMethod__1() Line 42   C#
mscorlib.dll!System.Lazy<Microsoft.CodeAnalysis.Host.IWorkspaceService>.CreateValue()   Unknown
mscorlib.dll!System.Lazy<Microsoft.CodeAnalysis.Host.IWorkspaceService>.LazyInitValue() Unknown
Microsoft.CodeAnalysis.Workspaces.dll!Microsoft.CodeAnalysis.Host.Mef.MefWorkspaceServices.GetService<Microsoft.CodeAnalysis.Host.IWorkspaceEventListenerService>() Line 60 C#
Microsoft.CodeAnalysis.Workspaces.dll!Microsoft.CodeAnalysis.Workspace.Dispose(bool finalize) Line 372  C#
Microsoft.VisualStudio.LanguageServices.dll!Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem.VisualStudioWorkspaceImpl.Dispose(bool finalize) Line 1407 C#
Microsoft.CodeAnalysis.Workspaces.dll!Microsoft.CodeAnalysis.Workspace.Dispose() Line 358   C#
sharwell commented 2 years ago

Pull request #48068 fixes this issue, but is blocked on #47951.