Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed mistake on shadow copying assembly loader. #1497

Merged
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 67 additions & 10 deletions src/OmniSharp.Host/Services/AnalyzerAssemblyLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ public class AnalyzerAssemblyLoader : IAnalyzerAssemblyLoader
private readonly Dictionary<string, Assembly> _loadedAssembliesByPath = new Dictionary<string, Assembly>();
private readonly Dictionary<string, AssemblyIdentity> _loadedAssemblyIdentitiesByPath = new Dictionary<string, AssemblyIdentity>();
private readonly Dictionary<AssemblyIdentity, Assembly> _loadedAssembliesByIdentity = new Dictionary<AssemblyIdentity, Assembly>();

private readonly Dictionary<string, HashSet<string>> _knownAssemblyPathsBySimpleName = new Dictionary<string, HashSet<string>>(StringComparer.OrdinalIgnoreCase);
private int _hookedAssemblyResolve;

public AnalyzerAssemblyLoader()
{
Expand Down Expand Up @@ -63,6 +63,7 @@ public Assembly LoadFromPath(string fullPath)

private Assembly LoadFromPathUncheckedCore(string fullPath, AssemblyIdentity identity = null)
{

// Check if we have already loaded an assembly with the same identity or from the given path.
Assembly loadedAssembly = null;
lock (_guard)
Expand Down Expand Up @@ -147,14 +148,6 @@ private AssemblyIdentity AddToCache(string fullPath, AssemblyIdentity identity)
return identity;
}

private Assembly LoadFromPathImpl(string fullPath)
{
string assemblyDirectory = CreateUniqueDirectoryForAssembly();
string shadowCopyPath = CopyFileAndResources(fullPath, assemblyDirectory);

return Assembly.LoadFrom(shadowCopyPath);
}

private static string CopyFileAndResources(string fullPath, string assemblyDirectory)
{
string fileNameWithExtension = Path.GetFileName(fullPath);
Expand Down Expand Up @@ -230,10 +223,74 @@ private string CreateUniqueDirectoryForProcess()
string directory = Path.Combine(_baseDirectory, guid);

Directory.CreateDirectory(directory);

return directory;
}

private Assembly LoadFromPathImpl(string originalPath)
{
string assemblyDirectory = CreateUniqueDirectoryForAssembly();
string shadowCopyPath = CopyFileAndResources(originalPath, assemblyDirectory);

if (Interlocked.CompareExchange(ref _hookedAssemblyResolve, 0, 1) == 0)
{
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
}

return Assembly.LoadFrom(shadowCopyPath);
}

private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
try
{
return Load(AppDomain.CurrentDomain.ApplyPolicy(args.Name));
}
catch
{
return null;
}
}

public Assembly Load(string displayName)
{
if (!AssemblyIdentity.TryParseDisplayName(displayName, out var requestedIdentity))
{
return null;
}

ImmutableArray<string> candidatePaths;
lock (_guard)
{

// First, check if this loader already loaded the requested assembly:
if (_loadedAssembliesByIdentity.TryGetValue(requestedIdentity, out var existingAssembly))
{
return existingAssembly;
}
// Second, check if an assembly file of the same simple name was registered with the loader:
if (!_knownAssemblyPathsBySimpleName.TryGetValue(requestedIdentity.Name, out var pathList))
{
return null;
}

candidatePaths = pathList.ToImmutableArray();
}

// Multiple assemblies of the same simple name but different identities might have been registered.
// Load the one that matches the requested identity (if any).
foreach (var candidatePath in candidatePaths)
{
var candidateIdentity = GetOrAddAssemblyIdentity(candidatePath);

if (requestedIdentity.Equals(candidateIdentity))
{
return LoadFromPathUncheckedCore(candidatePath, candidateIdentity);
}
}

return null;
}

private static AssemblyIdentity TryGetAssemblyIdentity(string filePath)
{
try
Expand Down