private RoAssembly LoadFromStreamCore(Stream peStream) { PEReader peReader = new PEReader(peStream); PEReader peReaderToDispose = peReader; // Ensure peReader is disposed immediately if we throw an exception before we're done. try { if (!peReader.HasMetadata) { throw new BadImageFormatException(SR.NoMetadataInPeImage); } string location = (peStream is FileStream fs) ? (fs.Name ?? string.Empty) : string.Empty; MetadataReader reader = peReader.GetMetadataReader(); RoAssembly newAssembly = new EcmaAssembly(this, peReader, reader, location); AssemblyNameData defNameData = newAssembly.GetAssemblyNameDataNoCopy(); byte[] pkt = defNameData.PublicKeyToken ?? Array.Empty <byte>(); if (pkt.Length == 0 && defNameData.PublicKey != null && defNameData.PublicKey.Length != 0) { pkt = defNameData.PublicKey.ComputePublicKeyToken(); } RoAssemblyName defName = new RoAssemblyName(defNameData.Name, defNameData.Version, defNameData.CultureName, pkt); Guid mvid = newAssembly.ManifestModule.ModuleVersionId; LoadedAssemblyEntry candidate = new LoadedAssemblyEntry(newAssembly, mvid); LoadedAssemblyEntry winner = _loadedAssemblies.GetOrAdd(defName, candidate); if (winner.Assembly == newAssembly) { // We won the race. RegisterForDisposal(peReader); peReaderToDispose = null; return(_binds.GetOrAdd(defName, winner.Assembly)); // What if we lost the race to bind the defName in the _binds list? Should we ignore it and return the newly created assembly // (like Assembly.LoadModule()) does or return the prior assembly (like we do if we lose the race to commit into _loadedAssemblies?) // There's no perfect answer here. Fundamentally, the dilemma comes about because our apis don't lets apps properly separate // the act of creating an Assembly object from the act of committing the TypeLoader to bind to it. // // We will choose to return the prior winner so that the api is consistent with itself. This is how other LoadFrom() // apis work and they're used a lot more than LoadModule(). } else { // We lost the race but check for a MVID mismatch. if (mvid != winner.Mvid) { throw new FileLoadException(SR.Format(SR.FileLoadDuplicateAssemblies, defName)); } } return(winner.Assembly); } finally { peReaderToDispose?.Dispose(); } }
private RoAssembly LoadFromStreamCore(Stream peStream) { PEReader peReader = new PEReader(peStream); PEReader?peReaderToDispose = peReader; // Ensure peReader is disposed immediately if we throw an exception before we're done. try { if (!peReader.HasMetadata) { throw new BadImageFormatException(SR.NoMetadataInPeImage); } string location = (peStream is FileStream fs) ? (fs.Name ?? string.Empty) : string.Empty; MetadataReader reader = peReader.GetMetadataReader(); RoAssembly candidate = new EcmaAssembly(this, peReader, reader, location); AssemblyNameData defNameData = candidate.GetAssemblyNameDataNoCopy(); byte[] pkt = defNameData.PublicKeyToken ?? Array.Empty <byte>(); if (pkt.Length == 0 && defNameData.PublicKey != null && defNameData.PublicKey.Length != 0) { pkt = defNameData.PublicKey.ComputePublicKeyToken() !; } RoAssemblyName defName = new RoAssemblyName(defNameData.Name, defNameData.Version, defNameData.CultureName, pkt, defNameData.Flags); RoAssembly winner = _loadedAssemblies.GetOrAdd(defName, candidate); if (winner == candidate) { // We won the race. RegisterForDisposal(peReader); peReaderToDispose = null; // We do not add to the _binds list because the binding list is only for assemblies that have been resolved through // the Resolve method. This allows the resolver to have complete control over selecting the appropriate assembly // based on Version, CultureName and PublicKeyToken. return(winner); } else { // We lost the race but check for a Mvid mismatch. if (candidate.ManifestModule.ModuleVersionId != winner.ManifestModule.ModuleVersionId) { throw new FileLoadException(SR.Format(SR.FileLoadDuplicateAssemblies, defName)); } } return(winner); } finally { peReaderToDispose?.Dispose(); } }