internal RoAssembly ResolveAssembly(RoAssemblyName refName) { Debug.Assert(refName != null); RoAssembly?assembly = TryResolveAssembly(refName, out Exception? e); return(assembly ?? throw e !); }
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(); } }
internal RoAssembly ResolveToAssemblyOrExceptionAssembly(RoAssemblyName refName) { Debug.Assert(refName != null); if (_binds.TryGetValue(refName, out RoAssembly? prior)) { return(prior); } RoAssembly assembly = TryFindAssemblyByCallingResolveHandler(refName); return(_binds.GetOrAdd(refName, assembly)); }
internal RoAssembly?TryResolveAssembly(RoAssemblyName refName, out Exception?e) { e = null; RoAssembly result = ResolveToAssemblyOrExceptionAssembly(refName); if (result is RoExceptionAssembly exceptionAssembly) { e = exceptionAssembly.Exception; return(null); } return(result); }
/// <summary> /// Resolves the supplied assembly name to an assembly. If an assembly was previously bound by to this name, that assembly is returned. /// Otherwise, the MetadataLoadContext calls the specified MetadataAssemblyResolver. If the resolver returns null, this method throws a FileNotFoundException. /// /// Note that this behavior matches the behavior of AssemblyLoadContext.LoadFromAssemblyName() resolve event but does not match the behavior of /// Assembly.ReflectionOnlyLoad(). (the latter gives up without raising its resolve event.) /// </summary> public Assembly LoadFromAssemblyName(AssemblyName assemblyName) { if (assemblyName is null) { throw new ArgumentNullException(nameof(assemblyName)); } if (IsDisposed) { throw new ObjectDisposedException(nameof(MetadataLoadContext)); } RoAssemblyName refName = assemblyName.ToRoAssemblyName(); return(ResolveAssembly(refName)); }
/// <summary> /// Resolves the supplied assembly name to an assembly. If an assembly was previously bound by to this name, that assembly is returned. /// Otherwise, the TypeLoader raises the Resolving event. If the event handler returns null, this method throws a FileNotFoundException. /// /// Note that this behavior matches the behavior of AssemblyLoadContext.LoadFromAssemblyName() but does not match the behavior of /// Assembly.ReflectionOnlyLoad(). (the latter gives up without raising the resolve event.) /// </summary> public Assembly LoadFromAssemblyName(AssemblyName assemblyName) { if (IsDisposed) { throw new ObjectDisposedException(nameof(TypeLoader)); } if (assemblyName == null) { throw new ArgumentNullException(nameof(assemblyName)); } RoAssemblyName refName = assemblyName.ToRoAssemblyName(); return(ResolveAssembly(refName)); }
private RoAssembly TryFindAssemblyByCallingResolveHandler(RoAssemblyName refName) { Debug.Assert(refName != null); Assembly?assembly = resolver?.Resolve(this, refName.ToAssemblyName()); if (assembly == null) { return(new RoExceptionAssembly(new FileNotFoundException(SR.Format(SR.FileNotFoundAssembly, refName.FullName)))); } if (!(assembly is RoAssembly roAssembly && roAssembly.Loader == this)) { throw new FileLoadException(SR.ExternalAssemblyReturnedByMetadataAssemblyResolver); } return(roAssembly); }
private RoAssembly TryFindAssemblyByRaisingResolveEvent(RoAssemblyName refName) { Debug.Assert(refName != null); Assembly assembly = Resolving?.Invoke(this, refName.ToAssemblyName()); if (assembly == null) { return(new RoExceptionAssembly(new FileNotFoundException(SR.Format(SR.FileNotFoundAssembly, refName.FullName)))); } if (!(assembly is RoAssembly roAssembly && roAssembly.Loader == this)) { throw new FileLoadException(SR.ExternalAssemblyReturnedByResolveHandler); } return(roAssembly); }
internal unsafe InternalManifestResourceInfo GetInternalManifestResourceInfo(string resourceName) { MetadataReader reader = Reader; InternalManifestResourceInfo result = default; ManifestResourceHandleCollection manifestResources = reader.ManifestResources; foreach (ManifestResourceHandle resourceHandle in manifestResources) { ManifestResource resource = resourceHandle.GetManifestResource(reader); if (resource.Name.Equals(resourceName, reader)) { result.Found = true; if (resource.Implementation.IsNil) { checked { // Embedded data resource result.ResourceLocation = ResourceLocation.Embedded | ResourceLocation.ContainedInManifestFile; PEReader pe = _guardedPEReader.PEReader; PEMemoryBlock resourceDirectory = pe.GetSectionData(pe.PEHeaders.CorHeader.ResourcesDirectory.RelativeVirtualAddress); BlobReader blobReader = resourceDirectory.GetReader((int)resource.Offset, resourceDirectory.Length - (int)resource.Offset); uint length = blobReader.ReadUInt32(); result.PointerToResource = blobReader.CurrentPointer; // Length check the size of the resource to ensure it fits in the PE file section, note, this is only safe as its in a checked region if (length + sizeof(int) > blobReader.Length) { throw new BadImageFormatException(); } result.SizeOfResource = length; } } else { if (resource.Implementation.Kind == HandleKind.AssemblyFile) { // Get file name result.ResourceLocation = default; AssemblyFile file = ((AssemblyFileHandle)resource.Implementation).GetAssemblyFile(reader); result.FileName = file.Name.GetString(reader); if (file.ContainsMetadata) { EcmaModule module = (EcmaModule)Assembly.GetModule(result.FileName); if (module == null) { throw new BadImageFormatException(SR.Format(SR.ManifestResourceInfoReferencedBadModule, result.FileName)); } result = module.GetInternalManifestResourceInfo(resourceName); } } else if (resource.Implementation.Kind == HandleKind.AssemblyReference) { // Resolve assembly reference result.ResourceLocation = ResourceLocation.ContainedInAnotherAssembly; RoAssemblyName destinationAssemblyName = ((AssemblyReferenceHandle)resource.Implementation).ToRoAssemblyName(reader); result.ReferencedAssembly = Loader.ResolveAssembly(destinationAssemblyName); } } } } return(result); }