Beispiel #1
0
        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();
            }
        }
        /// <summary>
        /// Collate an AssemblyData object for a single assembly.
        /// </summary>
        /// <param name="asm">the assembly to collect data on.</param>
        /// <returns>A pair of the name and data of the given assembly.</returns>
        public KeyValuePair <string, AssemblyData> AssembleAssembly(Assembly asm)
        {
            AssemblyName asmName = asm.GetName();

            var asmNameData = new AssemblyNameData()
            {
                Name           = asmName.Name,
                Version        = asmName.Version,
                Culture        = string.IsNullOrEmpty(asmName.CultureName) ? null : asmName.CultureName,
                PublicKeyToken = asmName.GetPublicKeyToken(),
            };

            Type[] types = asm.GetTypes();
            JsonDictionary <string, JsonDictionary <string, TypeData> > namespacedTypes = null;

            if (types.Length > 0)
            {
                namespacedTypes = new JsonDictionary <string, JsonDictionary <string, TypeData> >();
                foreach (Type type in types)
                {
                    if (!type.IsPublic)
                    {
                        continue;
                    }

                    // Some types don't have a namespace, but we still want to file them
                    string typeNamespace = type.Namespace ?? "";

                    if (!namespacedTypes.TryGetValue(typeNamespace, out JsonDictionary <string, TypeData> typeDictionary))
                    {
                        typeDictionary = new JsonDictionary <string, TypeData>();
                        namespacedTypes.Add(typeNamespace, typeDictionary);
                    }

                    TypeData typeData;
                    try
                    {
                        typeData = AssembleType(type);
                    }
                    catch (Exception e) when(e is ReflectionTypeLoadException || e is FileNotFoundException)
                    {
                        continue;
                    }

                    typeDictionary[type.Name] = typeData;
                }
            }

            var asmData = new AssemblyData()
            {
                AssemblyName = asmNameData,
                Types        = namespacedTypes != null && namespacedTypes.Count > 0 ? namespacedTypes : null,
            };

            return(new KeyValuePair <string, AssemblyData>(asmName.Name, asmData));
        }
        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();
            }
        }
Beispiel #4
0
        private static object Union(AssemblyNameData thisAsmName, AssemblyNameData thatAsmName)
        {
            if (thatAsmName.Version > thisAsmName.Version)
            {
                thisAsmName.Version = thatAsmName.Version;
            }

            if (thisAsmName.PublicKeyToken == null && thatAsmName.PublicKeyToken != null)
            {
                thisAsmName.PublicKeyToken = thatAsmName.PublicKeyToken;
            }

            return(thisAsmName);
        }
        /// <summary>
        /// Collate an AssemblyData object for a single assembly.
        /// </summary>
        /// <param name="asm">the assembly to collect data on.</param>
        /// <returns>A pair of the name and data of the given assembly.</returns>
        public static KeyValuePair <string, AssemblyData> AssembleAssembly(Assembly asm)
        {
            AssemblyName asmName = asm.GetName();

            var asmNameData = new AssemblyNameData()
            {
                Name           = asmName.Name,
                Version        = asmName.Version,
                Culture        = string.IsNullOrEmpty(asmName.CultureName) ? null : asmName.CultureName,
                PublicKeyToken = asmName.GetPublicKeyToken(),
            };

            Type[] types = asm.GetTypes();
            JsonCaseInsensitiveStringDictionary <JsonCaseInsensitiveStringDictionary <TypeData> > namespacedTypes = null;

            if (types.Any())
            {
                namespacedTypes = new JsonCaseInsensitiveStringDictionary <JsonCaseInsensitiveStringDictionary <TypeData> >();
                foreach (Type type in asm.GetTypes())
                {
                    if (!type.IsPublic)
                    {
                        continue;
                    }

                    // Some types don't have a namespace, but we still want to file them
                    string typeNamespace = type.Namespace ?? "";

                    if (!namespacedTypes.ContainsKey(typeNamespace))
                    {
                        namespacedTypes.Add(typeNamespace, new JsonCaseInsensitiveStringDictionary <TypeData>());
                    }

                    TypeData typeData = AssembleType(type);

                    namespacedTypes[typeNamespace][type.Name] = typeData;
                }
            }

            var asmData = new AssemblyData()
            {
                AssemblyName = asmNameData,
                Types        = namespacedTypes
            };

            return(new KeyValuePair <string, AssemblyData>(asmName.Name, asmData));
        }
Beispiel #6
0
        protected sealed override AssemblyNameData[] ComputeAssemblyReferences()
        {
            MetadataReader reader = Reader;

            AssemblyNameData[] assemblyReferences = new AssemblyNameData[reader.AssemblyReferences.Count];
            int index = 0;

            foreach (AssemblyReferenceHandle handle in reader.AssemblyReferences)
            {
                AssemblyReference ar   = handle.GetAssemblyReference(reader);
                AssemblyNameData  data = new AssemblyNameData();

                AssemblyNameFlags flags = ar.Flags.ToAssemblyNameFlags();
                data.Flags       = flags;
                data.Name        = ar.Name.GetString(reader);
                data.Version     = ar.Version.AdjustForUnspecifiedVersionComponents();
                data.CultureName = ar.Culture.GetStringOrNull(reader) ?? string.Empty;
                if ((flags & AssemblyNameFlags.PublicKey) != 0)
                {
                    byte[] pk = ar.PublicKeyOrToken.GetBlobBytes(reader);
                    data.PublicKey = pk;
                    if (pk.Length != 0)
                    {
                        // AssemblyName will automatically compute the PKT on demand but given that we're doing all this work and caching it, we might
                        // as well do this now.
                        data.PublicKeyToken = pk.ComputePublicKeyToken();
                    }
                }
                else
                {
                    data.PublicKeyToken = ar.PublicKeyOrToken.GetBlobBytes(reader);
                }

                assemblyReferences[index++] = data;
            }

            return(assemblyReferences);
        }
Beispiel #7
0
        protected sealed override AssemblyNameData ComputeNameData()
        {
            MetadataReader     reader = Reader;
            AssemblyDefinition ad     = AssemblyDefinition;
            AssemblyNameData   data   = new AssemblyNameData
            {
                Name        = ad.Name.GetString(reader),
                Version     = ad.Version,
                CultureName = ad.Culture.GetStringOrNull(reader) ?? string.Empty
            };

            byte[] pk = ad.PublicKey.GetBlobBytes(reader);
            data.PublicKey = pk;
            if (pk.Length != 0)
            {
                // AssemblyName will automatically compute the PKT on demand but given that we're doing all this work and caching it, we might
                // as well do this now.
                data.PublicKeyToken = pk.ComputePublicKeyToken();
            }

            AssemblyNameFlags anFlagsAndContentType = ad.Flags.ToAssemblyNameFlags() | AssemblyNameFlags.PublicKey;

            data.Flags = anFlagsAndContentType.ExtractAssemblyNameFlags();

            // We've finished setting the AssemblyName properties that actually pertain to binding and the Ecma-355
            // concept of an assembly name.
            //
            // The rest of the properties are properties historically set by the runtime Reflection and thumbtacked
            // onto the AssemblyName object in the CLR tradition of treating AssemblyName as a dumping ground for all
            // kinds of info. Nevertheless, some of this info is potentially useful and not exposed elsewhere on Assembly
            // so we'll be nice and set it.
            data.HashAlgorithm = ad.HashAlgorithm.ToConfigurationAssemblyHashAlgorithm();
            data.ContentType   = anFlagsAndContentType.ExtractAssemblyContentType();

            ManifestModule.GetPEKind(out PortableExecutableKinds peKind, out ImageFileMachine machine);
            switch (machine)
            {
            case ImageFileMachine.AMD64:
                data.ProcessorArchitecture = ProcessorArchitecture.Amd64;
                break;

            case ImageFileMachine.ARM:
                data.ProcessorArchitecture = ProcessorArchitecture.Arm;
                break;

            case ImageFileMachine.IA64:
                data.ProcessorArchitecture = ProcessorArchitecture.IA64;
                break;

            case ImageFileMachine.I386:
                if ((peKind & PortableExecutableKinds.Required32Bit) != 0)
                {
                    data.ProcessorArchitecture = ProcessorArchitecture.X86;
                }
                else
                {
                    data.ProcessorArchitecture = ProcessorArchitecture.MSIL;
                }
                break;

            default:
                // No real precedent for what to do here - CLR will never get as far as giving you an Assembly object
                // if the PE file specifies an unsupported machine. Since this Reflection implementation is a metadata inspection
                // layer, and the library will never make any decisions based on this value, throwing isn't really the best response here.
                data.ProcessorArchitecture = ProcessorArchitecture.None;
                break;
            }
            return(data);
        }