You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
An invariant of the compiler server is to produce the same results that would come from running csc / vbc directly. Analyzers are one place where it is hard to maintain this invariant. That is because the compiler server has to consider the totality of analyzers used for an entire build while csc / vbc just has to consider the analyzers for a specific project. Issues like address space pollution are an issue the server has to consider but csc / vbc can ignore.
One concrete case where this is a problem is when analyzer dependencies conflict. This is best illustrated with an example. Consider a solution which consisted of the following projects:
Project1.csproj
Uses Analyzer1 which has a dependency of Util.dll at version 1.0.0
Project2.csproj
Uses Analyzer2 which has a dependency of Util.dll at version 2.0.0
If these projects are build by csc / vbc both analyzers get their own clean address space and each load the correct version of Util.dll. In the compiler server though there are many cases which could cause one or the other to get the wrong copy of Util.dll and end up producing incorrect results. The easiest case is when the server runs on .NET Framework,. Util.dll is not strong named signed and then it's just a case of first load wins.
The analyzer consistency check in the compiler server was designed to spot cases where analyzer dependencies conflict and pre-emptively drop back to csc / vbc. This is done by just by loading all analyzer dependencies into the process, then comparing the MVID of the loaded DLL with the DLL on disk. If they're different then the compiler makes the conservative decision that we've hit address space pollution issues and drops back to csc / vbc.
This check is necessary but a few recent cases have shown the heuristic is too aggressive. The most common situation we've seen is when analyzers use Span<T> which brings System.Memory as a dependency. That will always be the netstandard2.0 version of System.Memory as analyzers must build against netstandard2.0. At the same time though it means the MVID check will always fail because at runtime we either load the net472 or netcoreapp version of System.Memory. Hence such analyzers, which are using Span<T> for perf, end up causing their compilations to always fall back to csc / vbc which is decidedly not performant.
The current analysis needs to be changed in the following ways:
The consistency check should not run on .NET Core because each analyzer goes into it's own AssemblyLoadContext. That means there is no cross anlayzer pollution anymore.
The consistency check should not consider DLLs that are loaded from the GAC or from the compiler directory. Such DLLs can reasonably be assumed to be a part of the compiler runtime. Falling back to csc / vbc will not change the load outcome.
The text was updated successfully, but these errors were encountered:
Issue dotnet#64826 outlines the core problem the analyzer consistency check is
hitting here and rationale for changing it. In short though this changes
our analyzer consistency check in the following ways:
1. It no longer applies on .NET Core. Analyzers get their own
`AssemblyLoadContext` hence dependency consistency is not an issue
2. Do not fail consistency check when a dependency is loaded from the
GAC
3. Do not fail consistency check when a dependency is loaded from the
compiler directory
closesdotnet#64826
Issue #64826 outlines the core problem the analyzer consistency check is
hitting here and rationale for changing it. In short though this changes
our analyzer consistency check in the following ways:
1. It no longer applies on .NET Core. Analyzers get their own
`AssemblyLoadContext` hence dependency consistency is not an issue
2. Do not fail consistency check when a dependency is loaded from the
GAC
3. Do not fail consistency check when a dependency is loaded from the
compiler directory
closes#64826
An invariant of the compiler server is to produce the same results that would come from running csc / vbc directly. Analyzers are one place where it is hard to maintain this invariant. That is because the compiler server has to consider the totality of analyzers used for an entire build while csc / vbc just has to consider the analyzers for a specific project. Issues like address space pollution are an issue the server has to consider but csc / vbc can ignore.
One concrete case where this is a problem is when analyzer dependencies conflict. This is best illustrated with an example. Consider a solution which consisted of the following projects:
If these projects are build by csc / vbc both analyzers get their own clean address space and each load the correct version of Util.dll. In the compiler server though there are many cases which could cause one or the other to get the wrong copy of Util.dll and end up producing incorrect results. The easiest case is when the server runs on .NET Framework,. Util.dll is not strong named signed and then it's just a case of first load wins.
The analyzer consistency check in the compiler server was designed to spot cases where analyzer dependencies conflict and pre-emptively drop back to csc / vbc. This is done by just by loading all analyzer dependencies into the process, then comparing the MVID of the loaded DLL with the DLL on disk. If they're different then the compiler makes the conservative decision that we've hit address space pollution issues and drops back to csc / vbc.
This check is necessary but a few recent cases have shown the heuristic is too aggressive. The most common situation we've seen is when analyzers use
Span<T>
which bringsSystem.Memory
as a dependency. That will always be thenetstandard2.0
version ofSystem.Memory
as analyzers must build againstnetstandard2.0
. At the same time though it means the MVID check will always fail because at runtime we either load thenet472
ornetcoreapp
version ofSystem.Memory
. Hence such analyzers, which are usingSpan<T>
for perf, end up causing their compilations to always fall back to csc / vbc which is decidedly not performant.The current analysis needs to be changed in the following ways:
AssemblyLoadContext
. That means there is no cross anlayzer pollution anymore.The text was updated successfully, but these errors were encountered: