Skip to content
Merged
Show file tree
Hide file tree
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
Original file line number Diff line number Diff line change
Expand Up @@ -568,12 +568,8 @@ private static object EncodedValueToRawValue(long val, CustomAttributeEncoding e
}
private static RuntimeType ResolveType(RuntimeModule scope, string typeName)
{
RuntimeType type = RuntimeTypeHandle.GetTypeByNameUsingCARules(typeName, scope);

if (type is null)
throw new InvalidOperationException(
SR.Format(SR.Arg_CATypeResolutionFailed, typeName));

RuntimeType type = TypeNameParser.GetTypeReferencedByCustomAttribute(typeName, scope);
Debug.Assert(type is not null);
return type;
}
#endregion
Expand Down Expand Up @@ -1859,12 +1855,12 @@ internal static bool IsDefined(RuntimeFieldInfo field, RuntimeType? caType)
out int sizeConst, out string? marshalTypeName, out string? marshalCookie, out int iidParamIndex);

RuntimeType? safeArrayUserDefinedType = string.IsNullOrEmpty(safeArrayUserDefinedTypeName) ? null :
RuntimeTypeHandle.GetTypeByNameUsingCARules(safeArrayUserDefinedTypeName, scope);
TypeNameParser.GetTypeReferencedByCustomAttribute(safeArrayUserDefinedTypeName, scope);
RuntimeType? marshalTypeRef = null;

try
{
marshalTypeRef = marshalTypeName is null ? null : RuntimeTypeHandle.GetTypeByNameUsingCARules(marshalTypeName, scope);
marshalTypeRef = marshalTypeName is null ? null : TypeNameParser.GetTypeReferencedByCustomAttribute(marshalTypeName, scope);
}
catch (TypeLoadException)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Loader;
using System.Text;
using System.Threading;
Expand All @@ -18,6 +20,8 @@ internal unsafe ref partial struct TypeNameParser
private bool _throwOnError;
private bool _ignoreCase;
private bool _extensibleParser;
private bool _requireAssemblyQualifiedName;
private bool _suppressContextualReflectionContext;
private Assembly? _requestingAssembly;
private Assembly? _topLevelAssembly;

Expand Down Expand Up @@ -80,6 +84,60 @@ internal unsafe ref partial struct TypeNameParser
}.Parse();
}

// Resolve type name referenced by a custom attribute metadata.
// It uses the standard Type.GetType(typeName, throwOnError: true) algorithm with the following modifications:
// - ContextualReflectionContext is not taken into account
// - The dependency between the returned type and the requesting assembly is recorded for the purpose of
// lifetime tracking of collectible types.
internal static RuntimeType GetTypeReferencedByCustomAttribute(string typeName, RuntimeModule scope)
{
ArgumentException.ThrowIfNullOrEmpty(typeName);

RuntimeAssembly requestingAssembly = scope.GetRuntimeAssembly();

RuntimeType? type = (RuntimeType?)new TypeNameParser(typeName)
{
_throwOnError = true,
_suppressContextualReflectionContext = true,
_requestingAssembly = requestingAssembly
}.Parse();

Debug.Assert(type != null);

RuntimeTypeHandle.RegisterCollectibleTypeDependency(type, requestingAssembly);

return type;
}

// Used by VM
internal static unsafe RuntimeType? GetTypeHelper(char* pTypeName, RuntimeAssembly? requestingAssembly,
bool throwOnError, bool requireAssemblyQualifiedName)
{
ReadOnlySpan<char> typeName = MemoryMarshal.CreateReadOnlySpanFromNullTerminated(pTypeName);

// Compat: Empty name throws TypeLoadException instead of
// the natural ArgumentException
if (typeName.Length == 0)
{
if (throwOnError)
throw new TypeLoadException(SR.Arg_TypeLoadNullStr);
return null;
}

RuntimeType? type = (RuntimeType?)new TypeNameParser(typeName)
{
_requestingAssembly = requestingAssembly,
_throwOnError = throwOnError,
_suppressContextualReflectionContext = true,
_requireAssemblyQualifiedName = requireAssemblyQualifiedName,
}.Parse();

if (type != null)
RuntimeTypeHandle.RegisterCollectibleTypeDependency(type, requestingAssembly);

return type;
}

private bool CheckTopLevelAssemblyQualifiedName()
{
if (_topLevelAssembly is not null)
Expand All @@ -104,7 +162,8 @@ private bool CheckTopLevelAssemblyQualifiedName()
}
else
{
assembly = RuntimeAssembly.InternalLoad(new AssemblyName(assemblyName), ref Unsafe.NullRef<StackCrawlMark>(), AssemblyLoadContext.CurrentContextualReflectionContext,
assembly = RuntimeAssembly.InternalLoad(new AssemblyName(assemblyName), ref Unsafe.NullRef<StackCrawlMark>(),
_suppressContextualReflectionContext ? null : AssemblyLoadContext.CurrentContextualReflectionContext,
requestingAssembly: (RuntimeAssembly?)_requestingAssembly, throwOnFileNotFound: _throwOnError);
}
return assembly;
Expand Down Expand Up @@ -153,6 +212,14 @@ private bool CheckTopLevelAssemblyQualifiedName()
{
if (assembly is null)
{
if (_requireAssemblyQualifiedName)
{
if (_throwOnError)
{
throw new TypeLoadException(SR.Format(SR.TypeLoad_ResolveType, EscapeTypeName(typeName)));
}
return null;
}
return GetTypeFromDefaultAssemblies(typeName, nestedTypeNames);
}

Expand Down
77 changes: 8 additions & 69 deletions src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,34 +39,6 @@ internal RuntimeType GetTypeChecked()
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern bool IsInstanceOfType(RuntimeType type, [NotNullWhen(true)] object? o);

[RequiresUnreferencedCode("MakeGenericType cannot be statically analyzed. It's not possible to guarantee the availability of requirements of the generic type.")]
internal static Type GetTypeHelper(Type typeStart, Type[]? genericArgs, IntPtr pModifiers, int cModifiers) // called by VM
=> GetTypeHelper(typeStart, genericArgs, new ReadOnlySpan<int>((void*)pModifiers, cModifiers));

[RequiresUnreferencedCode("MakeGenericType cannot be statically analyzed. It's not possible to guarantee the availability of requirements of the generic type.")]
internal static Type GetTypeHelper(Type typeStart, Type[]? genericArgs, ReadOnlySpan<int> modifiers)
{
Type type = typeStart;

if (genericArgs != null)
{
type = type.MakeGenericType(genericArgs);
}

for (int i = 0; i < modifiers.Length; i++)
{
type = (CorElementType)modifiers[i] switch
{
CorElementType.ELEMENT_TYPE_PTR => type.MakePointerType(),
CorElementType.ELEMENT_TYPE_BYREF => type.MakeByRefType(),
CorElementType.ELEMENT_TYPE_SZARRAY => type.MakeArrayType(),
_ => type.MakeArrayType(modifiers[++i])
};
}

return type;
}

/// <summary>
/// Returns a new <see cref="RuntimeTypeHandle"/> object created from a handle to a RuntimeType.
/// </summary>
Expand Down Expand Up @@ -539,47 +511,6 @@ internal static MdUtf8String GetUtf8Name(RuntimeType type)
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern IRuntimeMethodInfo GetDeclaringMethod(RuntimeType type);

[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeTypeHandle_GetTypeByName", StringMarshalling = StringMarshalling.Utf16)]
private static partial void GetTypeByName(string name, [MarshalAs(UnmanagedType.Bool)] bool throwOnError, [MarshalAs(UnmanagedType.Bool)] bool ignoreCase, StackCrawlMarkHandle stackMark,
ObjectHandleOnStack assemblyLoadContext,
ObjectHandleOnStack type, ObjectHandleOnStack keepalive);

internal static RuntimeType? GetTypeByName(string name, bool throwOnError, bool ignoreCase, ref StackCrawlMark stackMark,
AssemblyLoadContext assemblyLoadContext)
{
if (string.IsNullOrEmpty(name))
{
if (throwOnError)
throw new TypeLoadException(SR.Arg_TypeLoadNullStr);

return null;
}

RuntimeType? type = null;
object? keepAlive = null;
AssemblyLoadContext assemblyLoadContextStack = assemblyLoadContext;
GetTypeByName(name, throwOnError, ignoreCase,
new StackCrawlMarkHandle(ref stackMark),
ObjectHandleOnStack.Create(ref assemblyLoadContextStack),
ObjectHandleOnStack.Create(ref type), ObjectHandleOnStack.Create(ref keepAlive));
GC.KeepAlive(keepAlive);

return type;
}

[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeTypeHandle_GetTypeByNameUsingCARules", StringMarshalling = StringMarshalling.Utf16)]
private static partial void GetTypeByNameUsingCARules(string name, QCallModule scope, ObjectHandleOnStack type);

internal static RuntimeType GetTypeByNameUsingCARules(string name, RuntimeModule scope)
{
ArgumentException.ThrowIfNullOrEmpty(name);

RuntimeType? type = null;
GetTypeByNameUsingCARules(name, new QCallModule(ref scope), ObjectHandleOnStack.Create(ref type));

return type!;
}

[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeTypeHandle_GetInstantiation")]
internal static partial void GetInstantiation(QCallTypeHandle type, ObjectHandleOnStack types, Interop.BOOL fAsRuntimeTypeArray);

Expand Down Expand Up @@ -728,6 +659,14 @@ internal static MetadataImport GetMetadataImport(RuntimeType type)
return new MetadataImport(_GetMetadataImport(type), type);
}

[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeTypeHandle_RegisterCollectibleTypeDependency")]
private static partial void RegisterCollectibleTypeDependency(QCallTypeHandle type, QCallAssembly assembly);

internal static void RegisterCollectibleTypeDependency(RuntimeType type, RuntimeAssembly? assembly)
{
RegisterCollectibleTypeDependency(new QCallTypeHandle(ref type), new QCallAssembly(ref assembly!));
}

public void GetObjectData(SerializationInfo info, StreamingContext context)
{
throw new PlatformNotSupportedException();
Expand Down
6 changes: 3 additions & 3 deletions src/coreclr/vm/class.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1815,7 +1815,7 @@ TypeHandle MethodTable::SetupCoClassForInterface()

// Try to load the class using its name as a fully qualified name. If that fails,
// then we try to load it in the assembly of the current class.
CoClassType = TypeName::GetTypeUsingCASearchRules(ss.GetUnicode(), GetAssembly());
CoClassType = TypeName::GetTypeReferencedByCustomAttribute(ss.GetUnicode(), GetAssembly());

// Cache the coclass type
GetClass_NoLogging()->SetCoClassForInterface(CoClassType);
Expand Down Expand Up @@ -1862,7 +1862,7 @@ void MethodTable::GetEventInterfaceInfo(MethodTable **ppSrcItfClass, MethodTable

// Try to load the class using its name as a fully qualified name. If that fails,
// then we try to load it in the assembly of the current class.
SrcItfType = TypeName::GetTypeUsingCASearchRules(ss.GetUnicode(), GetAssembly());
SrcItfType = TypeName::GetTypeReferencedByCustomAttribute(ss.GetUnicode(), GetAssembly());

// Retrieve the COM event provider class name.
IfFailThrow(cap.GetNonNullString(&szName, &cbName));
Expand All @@ -1872,7 +1872,7 @@ void MethodTable::GetEventInterfaceInfo(MethodTable **ppSrcItfClass, MethodTable

// Try to load the class using its name as a fully qualified name. If that fails,
// then we try to load it in the assembly of the current class.
EventProvType = TypeName::GetTypeUsingCASearchRules(ss.GetUnicode(), GetAssembly());
EventProvType = TypeName::GetTypeReferencedByCustomAttribute(ss.GetUnicode(), GetAssembly());

// Set the source interface and event provider classes.
*ppSrcItfClass = SrcItfType.GetMethodTable();
Expand Down
4 changes: 3 additions & 1 deletion src/coreclr/vm/corelib.h
Original file line number Diff line number Diff line change
Expand Up @@ -352,14 +352,16 @@ DEFINE_METHOD(THREAD_START_EXCEPTION,EX_CTOR, .ctor,

DEFINE_CLASS(TYPE_HANDLE, System, RuntimeTypeHandle)
DEFINE_CLASS(RT_TYPE_HANDLE, System, RuntimeTypeHandle)
DEFINE_METHOD(RT_TYPE_HANDLE, GET_TYPE_HELPER, GetTypeHelper, SM_Type_ArrType_IntPtr_int_RetType)
DEFINE_METHOD(RT_TYPE_HANDLE, PVOID_CTOR, .ctor, IM_RuntimeType_RetVoid)
DEFINE_METHOD(RT_TYPE_HANDLE, GETVALUEINTERNAL, GetValueInternal, SM_RuntimeTypeHandle_RetIntPtr)
#ifdef FEATURE_COMINTEROP
DEFINE_METHOD(RT_TYPE_HANDLE, ALLOCATECOMOBJECT, AllocateComObject, SM_VoidPtr_RetObj)
#endif
DEFINE_FIELD(RT_TYPE_HANDLE, M_TYPE, m_type)

DEFINE_CLASS(TYPE_NAME_PARSER, Reflection, TypeNameParser)
DEFINE_METHOD(TYPE_NAME_PARSER, GET_TYPE_HELPER, GetTypeHelper, SM_Type_CharPtr_RuntimeAssembly_Bool_Bool_RetRuntimeType)

DEFINE_CLASS_U(Reflection, RtFieldInfo, NoClass)
DEFINE_FIELD_U(m_fieldHandle, ReflectFieldObject, m_pFD)
DEFINE_CLASS(RT_FIELD_INFO, Reflection, RtFieldInfo)
Expand Down
4 changes: 2 additions & 2 deletions src/coreclr/vm/customattribute.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ TypeHandle Attribute::GetTypeForEnum(LPCUTF8 szEnumName, COUNT_T cbEnumName, Dom
CONTRACTL_END;

StackSString sszEnumName(SString::Utf8, szEnumName, cbEnumName);
return TypeName::GetTypeUsingCASearchRules(sszEnumName.GetUTF8(), pDomainAssembly->GetAssembly());
return TypeName::GetTypeReferencedByCustomAttribute(sszEnumName.GetUnicode(), pDomainAssembly->GetAssembly());
}

/*static*/
Expand Down Expand Up @@ -1041,7 +1041,7 @@ TypeHandle COMCustomAttribute::GetTypeHandleFromBlob(Assembly *pCtorAssembly,
*pBlob += size;
szName[size] = 0;

RtnTypeHnd = TypeName::GetTypeUsingCASearchRules(szName, pModule->GetAssembly(), NULL, FALSE);
RtnTypeHnd = TypeName::GetTypeReferencedByCustomAttribute(szName, pModule->GetAssembly());
break;
}

Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/vm/dllimport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4525,7 +4525,7 @@ HRESULT FindPredefinedILStubMethod(MethodDesc *pTargetMD, DWORD dwStubFlags, Met
// Retrieve the type
//
TypeHandle stubClassType;
stubClassType = TypeName::GetTypeUsingCASearchRules(typeName.GetUnicode(), pTargetMT->GetAssembly());
stubClassType = TypeName::GetTypeReferencedByCustomAttribute(typeName.GetUnicode(), pTargetMT->GetAssembly());

MethodTable *pStubClassMT = stubClassType.AsMethodTable();

Expand Down
4 changes: 2 additions & 2 deletions src/coreclr/vm/interoputil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1837,7 +1837,7 @@ DefaultInterfaceType GetDefaultInterfaceForClassInternal(TypeHandle hndClass, Ty
{
GCX_COOP();

DefItfType = TypeName::GetTypeUsingCASearchRules(defItf.GetUnicode(), pClassMT->GetAssembly());
DefItfType = TypeName::GetTypeReferencedByCustomAttribute(defItf.GetUnicode(), pClassMT->GetAssembly());

// If the type handle isn't a named type, then throw an exception using
// the name of the type obtained from pCurrInterfaces.
Expand Down Expand Up @@ -2109,7 +2109,7 @@ void GetComSourceInterfacesForClass(MethodTable *pMT, CQuickArray<MethodTable *>
{
// Load the COM source interface specified in the CA.
TypeHandle ItfType;
ItfType = TypeName::GetTypeUsingCASearchRules(pCurrInterfaces, pMT->GetAssembly());
ItfType = TypeName::GetTypeReferencedByCustomAttribute(pCurrInterfaces, pMT->GetAssembly());

// If the type handle isn't a named type, then throw an exception using
// the name of the type obtained from pCurrInterfaces.
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/vm/metasig.h
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@

// static methods:
DEFINE_METASIG_T(SM(Int_IntPtr_Obj_RetException, i I j, C(EXCEPTION)))
DEFINE_METASIG_T(SM(Type_ArrType_IntPtr_int_RetType, C(TYPE) a(C(TYPE)) I i, C(TYPE) ))
DEFINE_METASIG_T(SM(Type_CharPtr_RuntimeAssembly_Bool_Bool_RetRuntimeType, P(u) C(ASSEMBLY) F F, C(CLASS)))
DEFINE_METASIG_T(SM(Type_RetIntPtr, C(TYPE), I))
DEFINE_METASIG(SM(RefIntPtr_IntPtr_IntPtr_Int_RetObj, r(I) I I i, j))
DEFINE_METASIG(SM(Obj_IntPtr_RetIntPtr, j I, I))
Expand Down
Loading