dotnet / runtime

.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.
https://docs.microsoft.com/dotnet/core/
MIT License
15.26k stars 4.73k forks source link

Assembly Resolution finding a mismatched version corrupts state and makes loading good version impossible #91952

Open Fabi0San opened 1 year ago

Fabi0San commented 1 year ago

Description

While trying to resolve an assembly for loading, if one of the stages finds a mismatched version, later resolution stages fail to load good version.

Reproduction Steps

Put an old version of the required assembly in the application process .exe folder, then subscribe an assembly loader that will pick the right version from elsewhere.

Alternatively, I suspect that attempting to call Assembly.Load(name) with the wrong version beside the .exe and then execute LoadFrom(pathToGoodVersion) will fail as well.

Expected behavior

Good version should always succeed to load.

Here are traces of what happens if the assembly is not found at stage:ApplicationAssemblies, stage:AppDomainAssemblyResolveEvent succeeds.

Rest
HasStack="True" ThreadID="55,320" ProcessorNumber="0" ClrInstanceID="10" AssemblyName="FluentAssertions, Version=6.7.0.0, Culture=neutral, PublicKeyToken=33f2691a05b67b6a" Stage="FindInLoadContext" AssemblyLoadContext="Default" Result="AssemblyNotFound" ResultAssemblyName="" ResultAssemblyPath="" ErrorMessage="Could not locate assembly" ActivityID="/#7520/1/206/"
HasStack="True" ThreadID="55,320" ProcessorNumber="0" ClrInstanceID="10" AssemblyName="FluentAssertions, Version=6.7.0.0, Culture=neutral, PublicKeyToken=33f2691a05b67b6a" Stage="ApplicationAssemblies" AssemblyLoadContext="Default" Result="AssemblyNotFound" ResultAssemblyName="" ResultAssemblyPath="" ErrorMessage="Could not locate assembly" ActivityID="/#7520/1/206/"
HasStack="True" ThreadID="55,320" ProcessorNumber="0" ClrInstanceID="10" AssemblyName="FluentAssertions, Version=6.7.0.0, Culture=neutral, PublicKeyToken=33f2691a05b67b6a" Stage="AssemblyLoadContextResolvingEvent" AssemblyLoadContext="Default" Result="AssemblyNotFound" ResultAssemblyName="" ResultAssemblyPath="" ErrorMessage="Could not locate assembly" ActivityID="/#7520/1/206/"
HasStack="True" ThreadID="55,320" ProcessorNumber="0" ClrInstanceID="10" AssemblyName="FluentAssertions, Version=6.7.0.0, Culture=neutral, PublicKeyToken=33f2691a05b67b6a" Stage="AppDomainAssemblyResolveEvent" AssemblyLoadContext="Default" Result="Success" ResultAssemblyName="FluentAssertions, Version=6.7.0.0, Culture=neutral, PublicKeyToken=33f2691a05b67b6a" ResultAssemblyPath="D:\src\subs\target\test\managedstore\Internal.Exchange.Test.ManagedStore.QTests.Common\bin\Debug\net6.0\FluentAssertions.dll" ErrorMessage="" ActivityID="/#7520/1/206/"

Actual behavior

If the mismatched version is ever rejected, no good version can be loaded.

Here are traces of what happens if the mismatched version is found at stage:ApplicationAssemblies, stage:AppDomainAssemblyResolveEvent succeeds.

Rest
HasStack="True" ThreadID="60,068" ProcessorNumber="0" ClrInstanceID="9" AssemblyName="FluentAssertions, Version=6.7.0.0, Culture=neutral, PublicKeyToken=33f2691a05b67b6a" Stage="FindInLoadContext" AssemblyLoadContext="Default" Result="AssemblyNotFound" ResultAssemblyName="" ResultAssemblyPath="" ErrorMessage="Could not locate assembly" ActivityID="/#57240/1/206/"
HasStack="True" ThreadID="60,068" ProcessorNumber="0" ClrInstanceID="9" AssemblyName="FluentAssertions, Version=6.7.0.0, Culture=neutral, PublicKeyToken=33f2691a05b67b6a" Stage="ApplicationAssemblies" AssemblyLoadContext="Default" Result="MismatchedAssemblyName" ResultAssemblyName="FluentAssertions, Version=5.6.0.0, Culture=neutral, PublicKeyToken=33f2691a05b67b6a" ResultAssemblyPath="D:\src\subs\target\test\tools\UniTP\bin\Debug\net6.0\FluentAssertions.dll" ErrorMessage="Requested version 6.7.0.0 is incompatible with found version 5.6.0.0" ActivityID="/#57240/1/206/"
HasStack="True" ThreadID="60,068" ProcessorNumber="0" ClrInstanceID="9" AssemblyName="FluentAssertions, Version=6.7.0.0, Culture=neutral, PublicKeyToken=33f2691a05b67b6a" Stage="AssemblyLoadContextResolvingEvent" AssemblyLoadContext="Default" Result="AssemblyNotFound" ResultAssemblyName="" ResultAssemblyPath="" ErrorMessage="Could not locate assembly" ActivityID="/#57240/1/206/"
HasStack="True" ThreadID="60,068" ProcessorNumber="0" ClrInstanceID="9" AssemblyName="FluentAssertions, Version=6.7.0.0, Culture=neutral, PublicKeyToken=33f2691a05b67b6a" Stage="AppDomainAssemblyResolveEvent" AssemblyLoadContext="Default" Result="Exception" ResultAssemblyName="" ResultAssemblyPath="" ErrorMessage="Could not load file or assembly 'FluentAssertions, Version=6.7.0.0, Culture=neutral, PublicKeyToken=33f2691a05b67b6a'." ActivityID="/#57240/1/206/"

Regression?

Yes, This did not happen in net472, but happens in net6.0

Known Workarounds

Avoid bad versions.

Configuration

net6.0 Windows x64

Other information

No response

ghost commented 1 year ago

Tagging subscribers to this area: @vitek-karas, @agocke, @vsadov See info in area-owners.md if you want to be subscribed.

Issue Details
### Description While trying to resolve an assembly for loading, if one of the stages finds a mismatched version, later resolution stages fail to load good version. ### Reproduction Steps Put an old version of the required assembly in the application process .exe folder, then subscribe an assembly loader that will pick the right version from elsewhere. Alternatively, I suspect that attempting to call Assembly.Load(name) with the wrong version beside the .exe and then execute LoadFrom(pathToGoodVersion) will fail as well. ### Expected behavior Good version should always succeed to load. Here are traces of what happens if the assembly is not found at stage:ApplicationAssemblies, stage:AppDomainAssemblyResolveEvent succeeds.
Rest
HasStack="True" ThreadID="55,320" ProcessorNumber="0" ClrInstanceID="10" AssemblyName="FluentAssertions, Version=6.7.0.0, Culture=neutral, PublicKeyToken=33f2691a05b67b6a" Stage="FindInLoadContext" AssemblyLoadContext="Default" Result="AssemblyNotFound" ResultAssemblyName="" ResultAssemblyPath="" ErrorMessage="Could not locate assembly" ActivityID="/#7520/1/206/"
HasStack="True" ThreadID="55,320" ProcessorNumber="0" ClrInstanceID="10" AssemblyName="FluentAssertions, Version=6.7.0.0, Culture=neutral, PublicKeyToken=33f2691a05b67b6a" Stage="ApplicationAssemblies" AssemblyLoadContext="Default" Result="AssemblyNotFound" ResultAssemblyName="" ResultAssemblyPath="" ErrorMessage="Could not locate assembly" ActivityID="/#7520/1/206/"
HasStack="True" ThreadID="55,320" ProcessorNumber="0" ClrInstanceID="10" AssemblyName="FluentAssertions, Version=6.7.0.0, Culture=neutral, PublicKeyToken=33f2691a05b67b6a" Stage="AssemblyLoadContextResolvingEvent" AssemblyLoadContext="Default" Result="AssemblyNotFound" ResultAssemblyName="" ResultAssemblyPath="" ErrorMessage="Could not locate assembly" ActivityID="/#7520/1/206/"
HasStack="True" ThreadID="55,320" ProcessorNumber="0" ClrInstanceID="10" AssemblyName="FluentAssertions, Version=6.7.0.0, Culture=neutral, PublicKeyToken=33f2691a05b67b6a" Stage="AppDomainAssemblyResolveEvent" AssemblyLoadContext="Default" Result="Success" ResultAssemblyName="FluentAssertions, Version=6.7.0.0, Culture=neutral, PublicKeyToken=33f2691a05b67b6a" ResultAssemblyPath="D:\src\subs\target\test\managedstore\Internal.Exchange.Test.ManagedStore.QTests.Common\bin\Debug\net6.0\FluentAssertions.dll" ErrorMessage="" ActivityID="/#7520/1/206/"
### Actual behavior If the mismatched version is ever rejected, no good version can be loaded. Here are traces of what happens if the mismatched version is found at stage:ApplicationAssemblies, stage:AppDomainAssemblyResolveEvent succeeds.
Rest
HasStack="True" ThreadID="60,068" ProcessorNumber="0" ClrInstanceID="9" AssemblyName="FluentAssertions, Version=6.7.0.0, Culture=neutral, PublicKeyToken=33f2691a05b67b6a" Stage="FindInLoadContext" AssemblyLoadContext="Default" Result="AssemblyNotFound" ResultAssemblyName="" ResultAssemblyPath="" ErrorMessage="Could not locate assembly" ActivityID="/#57240/1/206/"
HasStack="True" ThreadID="60,068" ProcessorNumber="0" ClrInstanceID="9" AssemblyName="FluentAssertions, Version=6.7.0.0, Culture=neutral, PublicKeyToken=33f2691a05b67b6a" Stage="ApplicationAssemblies" AssemblyLoadContext="Default" Result="MismatchedAssemblyName" ResultAssemblyName="FluentAssertions, Version=5.6.0.0, Culture=neutral, PublicKeyToken=33f2691a05b67b6a" ResultAssemblyPath="D:\src\subs\target\test\tools\UniTP\bin\Debug\net6.0\FluentAssertions.dll" ErrorMessage="Requested version 6.7.0.0 is incompatible with found version 5.6.0.0" ActivityID="/#57240/1/206/"
HasStack="True" ThreadID="60,068" ProcessorNumber="0" ClrInstanceID="9" AssemblyName="FluentAssertions, Version=6.7.0.0, Culture=neutral, PublicKeyToken=33f2691a05b67b6a" Stage="AssemblyLoadContextResolvingEvent" AssemblyLoadContext="Default" Result="AssemblyNotFound" ResultAssemblyName="" ResultAssemblyPath="" ErrorMessage="Could not locate assembly" ActivityID="/#57240/1/206/"
HasStack="True" ThreadID="60,068" ProcessorNumber="0" ClrInstanceID="9" AssemblyName="FluentAssertions, Version=6.7.0.0, Culture=neutral, PublicKeyToken=33f2691a05b67b6a" Stage="AppDomainAssemblyResolveEvent" AssemblyLoadContext="Default" Result="Exception" ResultAssemblyName="" ResultAssemblyPath="" ErrorMessage="Could not load file or assembly 'FluentAssertions, Version=6.7.0.0, Culture=neutral, PublicKeyToken=33f2691a05b67b6a'." ActivityID="/#57240/1/206/"
### Regression? Yes, This did not happen in net472, but happens in net6.0 ### Known Workarounds Avoid bad versions. ### Configuration net6.0 Windows x64 ### Other information _No response_
Author: Fabi0San
Assignees: -
Labels: `area-AssemblyLoader-coreclr`, `untriaged`, `needs-area-label`
Milestone: -