|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Collections.Generic;
using System.Configuration.Assemblies;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.SymbolStore;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Loader;
using System.Security;
using System.Threading;
namespace System.Reflection.Emit
{
public partial class AssemblyBuilder
{
[RequiresDynamicCode("Defining a dynamic assembly requires dynamic code.")]
[DynamicSecurityMethod] // Required to make Assembly.GetCallingAssembly reliable.
public static AssemblyBuilder DefineDynamicAssembly(AssemblyName name, AssemblyBuilderAccess access)
=> DefineDynamicAssembly(name, access, null, GetCallingAssembly());
[RequiresDynamicCode("Defining a dynamic assembly requires dynamic code.")]
[DynamicSecurityMethod] // Required to make Assembly.GetCallingAssembly reliable.
public static AssemblyBuilder DefineDynamicAssembly(
AssemblyName name,
AssemblyBuilderAccess access,
IEnumerable<CustomAttributeBuilder>? assemblyAttributes)
=> DefineDynamicAssembly(name, access, assemblyAttributes, GetCallingAssembly());
private static RuntimeAssemblyBuilder DefineDynamicAssembly(
AssemblyName name,
AssemblyBuilderAccess access,
IEnumerable<CustomAttributeBuilder>? assemblyAttributes,
Assembly? callingAssembly)
{
ArgumentNullException.ThrowIfNull(name);
if (access != AssemblyBuilderAccess.Run && access != AssemblyBuilderAccess.RunAndCollect)
{
throw new ArgumentException(SR.Format(SR.Arg_EnumIllegalVal, (int)access), nameof(access));
}
if (callingAssembly == null)
{
// Called either from interop or async delegate invocation. Rejecting because we don't
// know how to set the correct context of the new dynamic assembly.
throw new InvalidOperationException();
}
EnsureDynamicCodeSupported();
AssemblyLoadContext assemblyLoadContext =
(AssemblyLoadContext.CurrentContextualReflectionContext ?? AssemblyLoadContext.GetLoadContext(callingAssembly)) ??
throw new InvalidOperationException();
return new RuntimeAssemblyBuilder(name, access, assemblyLoadContext, assemblyAttributes);
}
}
internal sealed partial class RuntimeAssemblyBuilder : AssemblyBuilder
{
#region Internal Data Members
internal readonly AssemblyBuilderAccess _access;
private readonly RuntimeAssembly _internalAssembly;
private readonly RuntimeModuleBuilder _manifestModuleBuilder;
// Set to true if the manifest module was returned by code:DefineDynamicModule to the user
private bool _isManifestModuleUsedAsDefinedModule;
private const int AssemblyDefToken = 0x20000001;
internal object SyncRoot => InternalAssembly.SyncRoot;
internal RuntimeAssembly InternalAssembly => _internalAssembly;
#endregion
#region Constructor
internal RuntimeAssemblyBuilder(AssemblyName name,
AssemblyBuilderAccess access,
AssemblyLoadContext assemblyLoadContext,
IEnumerable<CustomAttributeBuilder>? assemblyAttributes)
{
Debug.Assert(name is not null);
_access = access;
_internalAssembly = CreateDynamicAssembly(assemblyLoadContext, name, access);
// Make sure that ManifestModule is properly initialized
// We need to do this before setting any CustomAttribute
// Note that this ModuleBuilder cannot be used for RefEmit yet
// because it hasn't been initialized.
// However, it can be used to set the custom attribute on the Assembly
_manifestModuleBuilder = new RuntimeModuleBuilder(this, (RuntimeModule)InternalAssembly.ManifestModule);
if (assemblyAttributes != null)
{
foreach (CustomAttributeBuilder assemblyAttribute in assemblyAttributes)
{
SetCustomAttribute(assemblyAttribute);
}
}
}
#endregion
#region DefineDynamicAssembly
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "AppDomain_CreateDynamicAssembly")]
private static unsafe partial void CreateDynamicAssembly(ObjectHandleOnStack assemblyLoadContext,
NativeAssemblyNameParts* pAssemblyName,
AssemblyHashAlgorithm hashAlgId,
AssemblyBuilderAccess access,
ObjectHandleOnStack retAssembly);
private static unsafe RuntimeAssembly CreateDynamicAssembly(AssemblyLoadContext assemblyLoadContext, AssemblyName name, AssemblyBuilderAccess access)
{
RuntimeAssembly? retAssembly = null;
byte[]? publicKey = name.GetPublicKey();
fixed (char* pName = name.Name)
fixed (char* pCultureName = name.CultureName)
fixed (byte* pPublicKey = publicKey)
{
NativeAssemblyNameParts nameParts = default;
nameParts._flags = name.RawFlags;
nameParts._pName = pName;
nameParts._pCultureName = pCultureName;
nameParts._pPublicKeyOrToken = pPublicKey;
nameParts._cbPublicKeyOrToken = (publicKey != null) ? publicKey.Length : 0;
nameParts.SetVersion(name.Version, defaultValue: 0);
#pragma warning disable SYSLIB0037 // AssemblyName.HashAlgorithm is obsolete
CreateDynamicAssembly(ObjectHandleOnStack.Create(ref assemblyLoadContext),
&nameParts,
name.HashAlgorithm,
access,
ObjectHandleOnStack.Create(ref retAssembly));
#pragma warning restore SYSLIB0037
}
return retAssembly!;
}
private static readonly object s_assemblyBuilderLock = new object();
internal static RuntimeAssemblyBuilder InternalDefineDynamicAssembly(
AssemblyName name,
AssemblyBuilderAccess access,
AssemblyLoadContext assemblyLoadContext,
IEnumerable<CustomAttributeBuilder>? assemblyAttributes)
{
lock (s_assemblyBuilderLock)
{
// We can only create dynamic assemblies in the current domain
return new RuntimeAssemblyBuilder(name,
access,
assemblyLoadContext,
assemblyAttributes);
}
}
#endregion
#region DefineDynamicModule
/// <summary>
/// Defines a named dynamic module. It is an error to define multiple
/// modules within an Assembly with the same name. This dynamic module is
/// a transient module.
/// </summary>
protected override ModuleBuilder DefineDynamicModuleCore(string name)
{
if (name[0] == '\0')
{
throw new ArgumentException(SR.Argument_InvalidName, nameof(name));
}
lock (SyncRoot)
{
// Create the dynamic module- only one ModuleBuilder per AssemblyBuilder can be created.
if (_isManifestModuleUsedAsDefinedModule)
{
throw new InvalidOperationException(SR.InvalidOperation_NoMultiModuleAssembly);
}
// We are reusing manifest module as user-defined dynamic module
_isManifestModuleUsedAsDefinedModule = true;
return _manifestModuleBuilder;
}
}
#endregion
/// <summary>
/// Helper to ensure the type name is unique underneath assemblyBuilder.
/// </summary>
internal void CheckTypeNameConflict(string strTypeName, TypeBuilder? enclosingType)
{
_manifestModuleBuilder.CheckTypeNameConflict(strTypeName, enclosingType);
}
#region ICustomAttributeProvider Members
public override object[] GetCustomAttributes(bool inherit) =>
InternalAssembly.GetCustomAttributes(inherit);
public override object[] GetCustomAttributes(Type attributeType, bool inherit) =>
InternalAssembly.GetCustomAttributes(attributeType, inherit);
public override bool IsDefined(Type attributeType, bool inherit) =>
InternalAssembly.IsDefined(attributeType, inherit);
public override IList<CustomAttributeData> GetCustomAttributesData() =>
InternalAssembly.GetCustomAttributesData();
#endregion
#region Assembly overrides
public override AssemblyName GetName(bool copiedName) => InternalAssembly.GetName(copiedName);
public override string? FullName => InternalAssembly.FullName;
[RequiresUnreferencedCode("Types might be removed by trimming. If the type name is a string literal, consider using Type.GetType instead.")]
public override Type? GetType(string name, bool throwOnError, bool ignoreCase) =>
InternalAssembly.GetType(name, throwOnError, ignoreCase);
public override Module ManifestModule => _manifestModuleBuilder.InternalModule;
public override bool ReflectionOnly => InternalAssembly.ReflectionOnly;
public override Module? GetModule(string name) => InternalAssembly.GetModule(name);
[RequiresUnreferencedCode("Assembly references might be removed")]
public override AssemblyName[] GetReferencedAssemblies() =>
InternalAssembly.GetReferencedAssemblies();
public override long HostContext => InternalAssembly.HostContext;
public override Module[] GetModules(bool getResourceModules) =>
InternalAssembly.GetModules(getResourceModules);
public override Module[] GetLoadedModules(bool getResourceModules) =>
InternalAssembly.GetLoadedModules(getResourceModules);
public override Assembly GetSatelliteAssembly(CultureInfo culture) =>
InternalAssembly.GetSatelliteAssembly(culture, null);
/// <summary>
/// Useful for binding to a very specific version of a satellite assembly
/// </summary>
public override Assembly GetSatelliteAssembly(CultureInfo culture, Version? version) =>
InternalAssembly.GetSatelliteAssembly(culture, version);
public override bool IsCollectible => InternalAssembly.IsCollectible;
#endregion
/// <param name="name">The name of module for the look up.</param>
/// <returns>Dynamic module with the specified name.</returns>
protected override ModuleBuilder? GetDynamicModuleCore(string name)
{
if (_isManifestModuleUsedAsDefinedModule)
{
if (RuntimeModuleBuilder.ManifestModuleName == name)
{
return _manifestModuleBuilder;
}
}
return null;
}
/// <summary>
/// Use this function if client decides to form the custom attribute blob themselves.
/// </summary>
protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan<byte> binaryAttribute)
{
lock (SyncRoot)
{
RuntimeTypeBuilder.DefineCustomAttribute(
_manifestModuleBuilder, // pass in the in-memory assembly module
AssemblyDefToken,
_manifestModuleBuilder.GetMethodMetadataToken(con),
binaryAttribute);
}
}
}
}
|