From 60ef787c2d0fa32b54ccb737016402cfe3b86d9e Mon Sep 17 00:00:00 2001 From: Aaron R Robinson Date: Thu, 21 Mar 2024 12:58:24 -0700 Subject: [PATCH 1/7] Remove helper method frames Convert _ParseAttributeUsageAttribute() to C#. --- .../Reflection/RuntimeCustomAttributeData.cs | 94 ++++++++++++++----- src/coreclr/vm/customattribute.cpp | 41 -------- src/coreclr/vm/customattribute.h | 1 - src/coreclr/vm/ecalllist.h | 3 +- 4 files changed, 73 insertions(+), 66 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttributeData.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttributeData.cs index 1b3032a24607c4..ed6a7bea2c02c3 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttributeData.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttributeData.cs @@ -9,6 +9,7 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; +using Internal; namespace System.Reflection { @@ -472,6 +473,7 @@ public override IList NamedArguments if (p.EncodedArgument is not null && p.EncodedArgument.CustomAttributeType.EncodedType != CustomAttributeEncoding.Undefined) { + Debug.Assert(p.MemberInfo is not null); namedArgs[j++] = new CustomAttributeNamedArgument( p.MemberInfo, new CustomAttributeTypedArgument(m_scope, p.EncodedArgument)); @@ -765,7 +767,7 @@ private static void ParseNamedArgs( } // Match name - if (!namedParam.MemberInfo.Name.Equals(argName)) + if (!namedParam.Name.Equals(argName)) { continue; } @@ -1057,12 +1059,29 @@ internal sealed class CustomAttributeCtorParameter(CustomAttributeType type) public CustomAttributeEncodedArgument? EncodedArgument { get; set; } } - internal sealed class CustomAttributeNamedParameter(MemberInfo memberInfo, CustomAttributeEncoding fieldOrProperty, CustomAttributeType type) + internal sealed class CustomAttributeNamedParameter { - public MemberInfo MemberInfo => memberInfo; - public CustomAttributeType CustomAttributeType => type; - public CustomAttributeEncoding FieldOrProperty => fieldOrProperty; + public CustomAttributeNamedParameter(MemberInfo memberInfo, CustomAttributeEncoding fieldOrProperty, CustomAttributeType type) + { + MemberInfo = memberInfo; + Name = MemberInfo.Name; + FieldOrProperty = fieldOrProperty; + CustomAttributeType = type; + } + + public CustomAttributeNamedParameter(string memberName, CustomAttributeEncoding fieldOrProperty, CustomAttributeType type) + { + MemberInfo = null; + Name = memberName; + FieldOrProperty = fieldOrProperty; + CustomAttributeType = type; + } + + public string Name { get; } + public CustomAttributeType CustomAttributeType { get; } + public CustomAttributeEncoding FieldOrProperty { get; } public CustomAttributeEncodedArgument? EncodedArgument { get; set; } + public MemberInfo? MemberInfo { get; } } internal sealed class CustomAttributeType @@ -1783,6 +1802,23 @@ internal static AttributeUsageAttribute GetAttributeUsage(RuntimeType decoratedA AttributeUsageAttribute? attributeUsageAttribute = null; + CustomAttributeCtorParameter[] ctorParams = + { + new CustomAttributeCtorParameter(new CustomAttributeType((RuntimeType)typeof(int))) + }; + + CustomAttributeNamedParameter[] namedParams = + { + new CustomAttributeNamedParameter( + "Inherited", + CustomAttributeEncoding.Property, + new CustomAttributeType((RuntimeType)typeof(bool))), + new CustomAttributeNamedParameter( + "AllowMultiple", + CustomAttributeEncoding.Property, + new CustomAttributeType((RuntimeType)typeof(bool))), + }; + for (int i = 0; i < car.Length; i++) { ref CustomAttributeRecord caRecord = ref car[i]; @@ -1794,8 +1830,26 @@ internal static AttributeUsageAttribute GetAttributeUsage(RuntimeType decoratedA if (attributeUsageAttribute is not null) throw new FormatException(SR.Format(SR.Format_AttributeUsage, attributeType)); - ParseAttributeUsageAttribute(caRecord.blob, out AttributeTargets targets, out bool inherited, out bool allowMultiple); - attributeUsageAttribute = new AttributeUsageAttribute(targets, allowMultiple, inherited); + CustomAttributeEncodedArgument.ParseAttributeArguments( + caRecord.blob, + ctorParams, + namedParams, + (RuntimeModule)typeof(AttributeUsageAttribute).Module); + + // Convert parsed attribute arguments + AttributeTargets attrTargets = ctorParams[0].EncodedArgument is not null + ? (AttributeTargets)ctorParams[0].EncodedArgument!.PrimitiveValue.Byte4 + : 0; + + bool inherited = namedParams[0].EncodedArgument is not null + ? namedParams[0].EncodedArgument!.PrimitiveValue.Byte4 != 0 + : true; // default + + bool allowMultiple = namedParams[1].EncodedArgument is not null + ? namedParams[1].EncodedArgument!.PrimitiveValue.Byte4 != 0 + : false; // default + + attributeUsageAttribute = new AttributeUsageAttribute(attrTargets, allowMultiple: allowMultiple, inherited: inherited); } return attributeUsageAttribute ?? AttributeUsageAttribute.Default; @@ -1839,16 +1893,6 @@ internal static object[] CreateAttributeArrayHelper(RuntimeType caType, int elem #endregion #region Private Static FCalls - [MethodImpl(MethodImplOptions.InternalCall)] - private static extern void _ParseAttributeUsageAttribute( - IntPtr pCa, int cCa, out int targets, out bool inherited, out bool allowMultiple); - private static void ParseAttributeUsageAttribute( - ConstArray ca, out AttributeTargets targets, out bool inherited, out bool allowMultiple) - { - _ParseAttributeUsageAttribute(ca.Signature, ca.Length, out int _targets, out inherited, out allowMultiple); - targets = (AttributeTargets)_targets; - } - [MethodImpl(MethodImplOptions.InternalCall)] private static extern object _CreateCaObject(RuntimeModule pModule, RuntimeType type, IRuntimeMethodInfo pCtor, byte** ppBlob, byte* pEndBlob, int* pcNamedArgs); private static object CreateCaObject(RuntimeModule module, RuntimeType type, IRuntimeMethodInfo ctor, ref IntPtr blob, IntPtr blobEnd, out int namedArgs) @@ -1918,12 +1962,18 @@ private static HashSet CreatePseudoCustomAttributeHashSet() private static void VerifyPseudoCustomAttribute(RuntimeType pca) { // If any of these are invariants are no longer true will have to - // re-architect the PCA product logic and test cases -- you've been warned! - Debug.Assert(pca.BaseType == typeof(Attribute), "Pseudo CA Error"); + // re-architect the PCA product logic and test cases. + Debug.Assert(pca.BaseType == typeof(Attribute), "Pseudo CA Error - Incorrect base type"); AttributeUsageAttribute usage = CustomAttribute.GetAttributeUsage(pca); - Debug.Assert(!usage.Inherited, "Pseudo CA Error"); - // AllowMultiple is true for TypeForwardedToAttribute - // Debug.Assert(usage.AllowMultiple == false, "Pseudo CA Error"); + Debug.Assert(!usage.Inherited, "Pseudo CA Error - Unexpected Inherited value"); + if (pca == typeof(TypeForwardedToAttribute)) + { + Debug.Assert(usage.AllowMultiple, "Pseudo CA Error - Unexpected AllowMultiple value"); + } + else + { + Debug.Assert(!usage.AllowMultiple, "Pseudo CA Error - Unexpected AllowMultiple value"); + } } #endregion diff --git a/src/coreclr/vm/customattribute.cpp b/src/coreclr/vm/customattribute.cpp index b86ca79db92819..5da4fef09bc052 100644 --- a/src/coreclr/vm/customattribute.cpp +++ b/src/coreclr/vm/customattribute.cpp @@ -481,47 +481,6 @@ FCIMPL6(LPVOID, COMCustomAttribute::CreateCaObject, ReflectModuleBaseObject* pAt } FCIMPLEND -FCIMPL5(VOID, COMCustomAttribute::ParseAttributeUsageAttribute, PVOID pData, ULONG cData, ULONG* pTargets, CLR_BOOL* pInherited, CLR_BOOL* pAllowMultiple) -{ - FCALL_CONTRACT; - - int inherited = 0; - int allowMultiple = 1; - - { - CustomAttributeParser ca(pData, cData); - - CaArg args[1]; - args[0].InitEnum(SERIALIZATION_TYPE_I4, 0); - if (FAILED(::ParseKnownCaArgs(ca, args, ARRAY_SIZE(args)))) - { - HELPER_METHOD_FRAME_BEGIN_0(); - COMPlusThrow(kCustomAttributeFormatException); - HELPER_METHOD_FRAME_END(); - } - - *pTargets = args[0].val.u4; - - CaNamedArg namedArgs[2]; - CaType namedArgTypes[2]; - namedArgTypes[inherited].Init(SERIALIZATION_TYPE_BOOLEAN); - namedArgTypes[allowMultiple].Init(SERIALIZATION_TYPE_BOOLEAN); - namedArgs[inherited].Init("Inherited", SERIALIZATION_TYPE_PROPERTY, namedArgTypes[inherited], TRUE); - namedArgs[allowMultiple].Init("AllowMultiple", SERIALIZATION_TYPE_PROPERTY, namedArgTypes[allowMultiple], FALSE); - if (FAILED(::ParseKnownCaNamedArgs(ca, namedArgs, ARRAY_SIZE(namedArgs)))) - { - HELPER_METHOD_FRAME_BEGIN_0(); - COMPlusThrow(kCustomAttributeFormatException); - HELPER_METHOD_FRAME_END(); - } - - *pInherited = namedArgs[inherited].val.boolean == TRUE; - *pAllowMultiple = namedArgs[allowMultiple].val.boolean == TRUE; - } -} -FCIMPLEND - - FCIMPL7(void, COMCustomAttribute::GetPropertyOrFieldData, ReflectModuleBaseObject *pModuleUNSAFE, BYTE** ppBlobStart, BYTE* pBlobEnd, STRINGREF* pName, CLR_BOOL* pbIsProperty, OBJECTREF* pType, OBJECTREF* value) { FCALL_CONTRACT; diff --git a/src/coreclr/vm/customattribute.h b/src/coreclr/vm/customattribute.h index 14ce07c785d5c8..10be7f36ebb752 100644 --- a/src/coreclr/vm/customattribute.h +++ b/src/coreclr/vm/customattribute.h @@ -29,7 +29,6 @@ class COMCustomAttribute public: // custom attributes utility functions - static FCDECL5(VOID, ParseAttributeUsageAttribute, PVOID pData, ULONG cData, ULONG* pTargets, CLR_BOOL* pInherited, CLR_BOOL* pAllowMultiple); static FCDECL6(LPVOID, CreateCaObject, ReflectModuleBaseObject* pAttributedModuleUNSAFE, ReflectClassBaseObject* pCaTypeUNSAFE, ReflectMethodObject *pMethodUNSAFE, BYTE** ppBlob, BYTE* pEndBlob, INT32* pcNamedArgs); static FCDECL7(void, GetPropertyOrFieldData, ReflectModuleBaseObject *pModuleUNSAFE, BYTE** ppBlobStart, BYTE* pBlobEnd, STRINGREF* pName, CLR_BOOL* pbIsProperty, OBJECTREF* pType, OBJECTREF* value); diff --git a/src/coreclr/vm/ecalllist.h b/src/coreclr/vm/ecalllist.h index fac53467d4c60c..4e7942c93b2dd9 100644 --- a/src/coreclr/vm/ecalllist.h +++ b/src/coreclr/vm/ecalllist.h @@ -234,7 +234,7 @@ FCFuncStart(gCOMFieldHandleNewFuncs) FCFuncElement("GetLoaderAllocator", RuntimeFieldHandle::GetLoaderAllocator) FCFuncElement("IsFastPathSupported", RuntimeFieldHandle::IsFastPathSupported) FCFuncElement("GetInstanceFieldOffset", RuntimeFieldHandle::GetInstanceFieldOffset) - FCFuncElement("GetStaticFieldAddress", RuntimeFieldHandle::GetStaticFieldAddress) + FCFuncElement("GetStaticFieldAddress", RuntimeFieldHandle::GetStaticFieldAddress) FCFuncEnd() FCFuncStart(gCOMModuleHandleFuncs) @@ -245,7 +245,6 @@ FCFuncStart(gCOMModuleHandleFuncs) FCFuncEnd() FCFuncStart(gCOMCustomAttributeFuncs) - FCFuncElement("_ParseAttributeUsageAttribute", COMCustomAttribute::ParseAttributeUsageAttribute) FCFuncElement("_CreateCaObject", COMCustomAttribute::CreateCaObject) FCFuncElement("_GetPropertyOrFieldData", COMCustomAttribute::GetPropertyOrFieldData) FCFuncEnd() From 6ad52e22066a125a21a060c85936992e31fc9a1d Mon Sep 17 00:00:00 2001 From: Aaron R Robinson Date: Thu, 21 Mar 2024 18:47:35 -0700 Subject: [PATCH 2/7] Non-building changes for custom attribute functions from FCalls to QCalls. --- .../Reflection/RuntimeCustomAttributeData.cs | 82 +++-- .../src/System/RuntimeType.CoreCLR.cs | 2 + src/coreclr/vm/customattribute.cpp | 317 ++++++++++-------- src/coreclr/vm/customattribute.h | 65 +--- src/coreclr/vm/ecalllist.h | 6 - src/coreclr/vm/qcallentrypoints.cpp | 2 + 6 files changed, 252 insertions(+), 222 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttributeData.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttributeData.cs index ed6a7bea2c02c3..b51ce3fe77cb8a 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttributeData.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttributeData.cs @@ -1133,7 +1133,7 @@ public CustomAttributeType(RuntimeType parameterType) public Type? EnumType { get; } } - internal static unsafe class CustomAttribute + internal static unsafe partial class CustomAttribute { #region Internal Static Members internal static bool IsDefined(RuntimeType type, RuntimeType? caType, bool inherit) @@ -1545,7 +1545,7 @@ private static void AddCustomAttributes( object attribute; if (ctorWithParameters is not null) { - attribute = CreateCaObject(decoratedModule, attributeType, ctorWithParameters, ref blobStart, blobEnd, out cNamedArgs); + attribute = CreateCustomAttributeInstance(decoratedModule, attributeType, ctorWithParameters, ref blobStart, blobEnd, out cNamedArgs); } else { @@ -1892,32 +1892,68 @@ internal static object[] CreateAttributeArrayHelper(RuntimeType caType, int elem } #endregion - #region Private Static FCalls - [MethodImpl(MethodImplOptions.InternalCall)] - private static extern object _CreateCaObject(RuntimeModule pModule, RuntimeType type, IRuntimeMethodInfo pCtor, byte** ppBlob, byte* pEndBlob, int* pcNamedArgs); - private static object CreateCaObject(RuntimeModule module, RuntimeType type, IRuntimeMethodInfo ctor, ref IntPtr blob, IntPtr blobEnd, out int namedArgs) - { - byte* pBlob = (byte*)blob; - byte* pBlobEnd = (byte*)blobEnd; - int cNamedArgs; - object ca = _CreateCaObject(module, type, ctor, &pBlob, pBlobEnd, &cNamedArgs); - blob = (IntPtr)pBlob; - namedArgs = cNamedArgs; - return ca; - } + [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "CustomAttribute_CreateCustomAttributeInstance")] + private static partial void CreateCustomAttributeInstance( + ObjectHandleOnStack pModule, + ObjectHandleOnStack type, + ObjectHandleOnStack pCtor, + ref IntPtr ppBlob, + IntPtr pEndBlob, + out int pcNamedArgs, + ObjectHandleOnStack instance); + + private static object CreateCustomAttributeInstance(RuntimeModule module, RuntimeType type, IRuntimeMethodInfo ctor, ref IntPtr blob, IntPtr blobEnd, out int namedArgs) + { + if (module is null) + { + throw new ArgumentNullException(SR.Arg_InvalidHandle); + } + + object? result = null; + CreateCustomAttributeInstance( + ObjectHandleOnStack.Create(ref module), + ObjectHandleOnStack.Create(ref type), + ObjectHandleOnStack.Create(ref ctor), + ref blob, + blobEnd, + out namedArgs, + ObjectHandleOnStack.Create(ref result)); + return result!; + } + + [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "CustomAttribute_CreateCustomAttributeInstance", StringMarshalling = StringMarshalling.Utf16)] + private static partial void CreatePropertyOrFieldData( + ObjectHandleOnStack pModule, + ref IntPtr ppBlobStart, + IntPtr pBlobEnd, + ObjectHandleOnStack name, + [MarshalAs(UnmanagedType.U1)] out bool bIsProperty, + ObjectHandleOnStack type, + ObjectHandleOnStack value); - [MethodImpl(MethodImplOptions.InternalCall)] - private static extern void _GetPropertyOrFieldData( - RuntimeModule pModule, byte** ppBlobStart, byte* pBlobEnd, out string name, out bool bIsProperty, out RuntimeType type, out object value); private static void GetPropertyOrFieldData( RuntimeModule module, ref IntPtr blobStart, IntPtr blobEnd, out string name, out bool isProperty, out RuntimeType? type, out object? value) { - byte* pBlobStart = (byte*)blobStart; - _GetPropertyOrFieldData( - module, &pBlobStart, (byte*)blobEnd, out name, out isProperty, out type, out value); - blobStart = (IntPtr)pBlobStart; + if (module is null) + { + throw new ArgumentNullException(SR.Arg_InvalidHandle); + } + + string? nameLocal = null; + RuntimeType? typeLocal = null; + object? valueLocal = null; + CreatePropertyOrFieldData( + ObjectHandleOnStack.Create(ref module), + ref blobStart, + blobEnd, + ObjectHandleOnStack.Create(ref nameLocal), + out isProperty, + ObjectHandleOnStack.Create(ref typeLocal), + ObjectHandleOnStack.Create(ref valueLocal)); + name = nameLocal!; + type = typeLocal; + value = valueLocal; } - #endregion } internal static class PseudoCustomAttribute diff --git a/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs index 00a8d78685d4d9..6a1fae9e05c706 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs @@ -2373,7 +2373,9 @@ private static bool FilterApplyMethodBase( #region Private Data Members #pragma warning disable CA1823 +#pragma warning disable CS0169 private readonly object m_keepalive; // This will be filled with a LoaderAllocator reference when this RuntimeType represents a collectible type +#pragma warning restore CS0169 #pragma warning restore CA1823 private IntPtr m_cache; internal IntPtr m_handle; diff --git a/src/coreclr/vm/customattribute.cpp b/src/coreclr/vm/customattribute.cpp index 5da4fef09bc052..b612a3373890c2 100644 --- a/src/coreclr/vm/customattribute.cpp +++ b/src/coreclr/vm/customattribute.cpp @@ -349,9 +349,20 @@ HRESULT Attribute::ParseAttributeArgumentValues( return hr; } -FCIMPL6(LPVOID, COMCustomAttribute::CreateCaObject, ReflectModuleBaseObject* pAttributedModuleUNSAFE, ReflectClassBaseObject* pCaTypeUNSAFE, ReflectMethodObject *pMethodUNSAFE, BYTE** ppBlob, BYTE* pEndBlob, INT32* pcNamedArgs) +extern "C" void QCALLTYPE CustomAttribute_CreateCustomAttributeInstance( + QCall::ObjectHandleOnStack pAttributedModule, + QCall::ObjectHandleOnStack pCaType, + QCall::ObjectHandleOnStack pMethod, + BYTE** ppBlob, + BYTE* pEndBlob, + INT32* pcNamedArgs, + QCall::ObjectHandleOnStack result) { - FCALL_CONTRACT; + QCALL_CONTRACT; + + BEGIN_QCALL; + + GCX_COOP(); struct { @@ -360,20 +371,19 @@ FCIMPL6(LPVOID, COMCustomAttribute::CreateCaObject, ReflectModuleBaseObject* pAt REFLECTMETHODREF refCtor; REFLECTMODULEBASEREF refAttributedModule; } gc; - gc.refCaType = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(pCaTypeUNSAFE); - TypeHandle th = gc.refCaType->GetType(); - + gc.refCaType = NULL; gc.ca = NULL; - gc.refCtor = (REFLECTMETHODREF)ObjectToOBJECTREF(pMethodUNSAFE); - gc.refAttributedModule = (REFLECTMODULEBASEREF)ObjectToOBJECTREF(pAttributedModuleUNSAFE); - - if(gc.refAttributedModule == NULL) - FCThrowRes(kArgumentNullException, W("Arg_InvalidHandle")); + gc.refCtor = NULL; + gc.refAttributedModule = NULL; + GCPROTECT_BEGIN(gc); + { + gc.refCaType = (REFLECTCLASSBASEREF)pCaType.Get(); + gc.refCtor = (REFLECTMETHODREF)pMethod.Get(); + gc.refAttributedModule = (REFLECTMODULEBASEREF)pAttributedModule.Get(); - MethodDesc* pCtorMD = gc.refCtor->GetMethod(); + MethodDesc* pCtorMD = gc.refCtor->GetMethod(); + TypeHandle th = gc.refCaType->GetType(); - HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc); - { MethodDescCallSite ctorCallSite(pCtorMD, th); MetaSig* pSig = ctorCallSite.GetMetaSig(); BYTE* pBlob = *ppBlob; @@ -420,7 +430,7 @@ FCIMPL6(LPVOID, COMCustomAttribute::CreateCaObject, ReflectModuleBaseObject* pAt if (th.IsArray()) // get the array element th = th.GetArrayElementTypeHandle(); - ARG_SLOT data = GetDataFromBlob(pCtorMD->GetAssembly(), (CorSerializationType)type, th, &pBlob, pEndBlob, gc.refAttributedModule->GetModule(), &bObjectCreated); + ARG_SLOT data = COMCustomAttribute::GetDataFromBlob(pCtorMD->GetAssembly(), (CorSerializationType)type, th, &pBlob, pEndBlob, gc.refAttributedModule->GetModule(), &bObjectCreated); if (bObjectCreated) argToProtect[i] = ArgSlotToObj(data); else @@ -474,171 +484,188 @@ FCIMPL6(LPVOID, COMCustomAttribute::CreateCaObject, ReflectModuleBaseObject* pAt args[0] = PtrToArgSlot(OBJECTREFToObject(gc.ca)->UnBox()); ctorCallSite.CallWithValueTypes(args); - } - HELPER_METHOD_FRAME_END(); - return OBJECTREFToObject(gc.ca); + result.Set(gc.ca); + } + GCPROTECT_END(); + END_QCALL; } -FCIMPLEND -FCIMPL7(void, COMCustomAttribute::GetPropertyOrFieldData, ReflectModuleBaseObject *pModuleUNSAFE, BYTE** ppBlobStart, BYTE* pBlobEnd, STRINGREF* pName, CLR_BOOL* pbIsProperty, OBJECTREF* pType, OBJECTREF* value) +extern "C" void QCALLTYPE CustomAttribute_CreatePropertyOrFieldData( + QCall::ObjectHandleOnStack pModuleObj, + BYTE** ppBlobStart, + BYTE* pBlobEnd, + QCall::ObjectHandleOnStack pName, + bool* pbIsProperty, + QCall::ObjectHandleOnStack pType, + QCall::ObjectHandleOnStack pValue) { - FCALL_CONTRACT; + QCALL_CONTRACT; + + BEGIN_QCALL; BYTE* pBlob = *ppBlobStart; - *pType = NULL; - REFLECTMODULEBASEREF refModule = (REFLECTMODULEBASEREF)ObjectToOBJECTREF(pModuleUNSAFE); + GCX_COOP(); - if(refModule == NULL) - FCThrowResVoid(kArgumentNullException, W("Arg_InvalidHandle")); + struct + { + OBJECTREF Name; + OBJECTREF Type; + OBJECTREF Value; + } gc; + gc.Name = NULL; + gc.Type = NULL; + gc.Value = NULL; + GCPROTECT_BEGIN(gc); - Module *pModule = refModule->GetModule(); + Module *pModule = pModuleObj.Get()->GetModule(); - HELPER_METHOD_FRAME_BEGIN_1(refModule); - { - Assembly *pCtorAssembly = NULL; + Assembly *pCtorAssembly = NULL; - MethodTable *pMTValue = NULL; - CorSerializationType arrayType = SERIALIZATION_TYPE_BOOLEAN; - BOOL bObjectCreated = FALSE; - TypeHandle nullTH; + MethodTable *pMTValue = NULL; + CorSerializationType arrayType = SERIALIZATION_TYPE_BOOLEAN; + BOOL bObjectCreated = FALSE; + TypeHandle nullTH; - if (pBlob + 2 > pBlobEnd) - COMPlusThrow(kCustomAttributeFormatException); + if (pBlob + 2 > pBlobEnd) + COMPlusThrow(kCustomAttributeFormatException); - // get whether it is a field or a property - CorSerializationType propOrField = (CorSerializationType)*pBlob; - pBlob++; - if (propOrField == SERIALIZATION_TYPE_FIELD) - *pbIsProperty = FALSE; - else if (propOrField == SERIALIZATION_TYPE_PROPERTY) - *pbIsProperty = TRUE; - else + // get whether it is a field or a property + CorSerializationType propOrField = (CorSerializationType)*pBlob; + pBlob++; + if (propOrField == SERIALIZATION_TYPE_FIELD) + *pbIsProperty = FALSE; + else if (propOrField == SERIALIZATION_TYPE_PROPERTY) + *pbIsProperty = TRUE; + else + COMPlusThrow(kCustomAttributeFormatException); + + // get the type of the field + CorSerializationType fieldType = (CorSerializationType)*pBlob; + pBlob++; + if (fieldType == SERIALIZATION_TYPE_SZARRAY) + { + arrayType = (CorSerializationType)*pBlob; + + if (pBlob + 1 > pBlobEnd) COMPlusThrow(kCustomAttributeFormatException); - // get the type of the field - CorSerializationType fieldType = (CorSerializationType)*pBlob; pBlob++; - if (fieldType == SERIALIZATION_TYPE_SZARRAY) - { - arrayType = (CorSerializationType)*pBlob; + } + if (fieldType == SERIALIZATION_TYPE_ENUM || arrayType == SERIALIZATION_TYPE_ENUM) + { + // get the enum type + ReflectClassBaseObject *pEnum = + (ReflectClassBaseObject*)OBJECTREFToObject(ArgSlotToObj(GetDataFromBlob( + pCtorAssembly, SERIALIZATION_TYPE_TYPE, nullTH, &pBlob, pBlobEnd, pModule, &bObjectCreated))); - if (pBlob + 1 > pBlobEnd) - COMPlusThrow(kCustomAttributeFormatException); + if (pEnum == NULL) + COMPlusThrow(kCustomAttributeFormatException); - pBlob++; - } - if (fieldType == SERIALIZATION_TYPE_ENUM || arrayType == SERIALIZATION_TYPE_ENUM) - { - // get the enum type - ReflectClassBaseObject *pEnum = - (ReflectClassBaseObject*)OBJECTREFToObject(ArgSlotToObj(GetDataFromBlob( - pCtorAssembly, SERIALIZATION_TYPE_TYPE, nullTH, &pBlob, pBlobEnd, pModule, &bObjectCreated))); + _ASSERTE(bObjectCreated); - if (pEnum == NULL) - COMPlusThrow(kCustomAttributeFormatException); + TypeHandle th = pEnum->GetType(); + _ASSERTE(th.IsEnum()); - _ASSERTE(bObjectCreated); + pMTValue = th.AsMethodTable(); + if (fieldType == SERIALIZATION_TYPE_ENUM) + // load the enum type to pass it back + gc.Type = th.GetManagedClassObject(); + else + nullTH = th; + } - TypeHandle th = pEnum->GetType(); - _ASSERTE(th.IsEnum()); + // get the string representing the field/property name + gc.Name = ArgSlotToString(GetDataFromBlob( + pCtorAssembly, SERIALIZATION_TYPE_STRING, nullTH, &pBlob, pBlobEnd, pModule, &bObjectCreated)); + _ASSERTE(bObjectCreated || gc.Name == NULL); - pMTValue = th.AsMethodTable(); - if (fieldType == SERIALIZATION_TYPE_ENUM) - // load the enum type to pass it back - *pType = th.GetManagedClassObject(); - else - nullTH = th; - } - - // get the string representing the field/property name - *pName = ArgSlotToString(GetDataFromBlob( - pCtorAssembly, SERIALIZATION_TYPE_STRING, nullTH, &pBlob, pBlobEnd, pModule, &bObjectCreated)); - _ASSERTE(bObjectCreated || *pName == NULL); + // create the object and return it + switch (fieldType) + { + case SERIALIZATION_TYPE_TAGGED_OBJECT: + gc.Type = g_pObjectClass->GetManagedClassObject(); + FALLTHROUGH; + case SERIALIZATION_TYPE_TYPE: + case SERIALIZATION_TYPE_STRING: + gc.Value = ArgSlotToObj(GetDataFromBlob( + pCtorAssembly, fieldType, nullTH, &pBlob, pBlobEnd, pModule, &bObjectCreated)); + _ASSERTE(bObjectCreated || gc.Value == NULL); - // create the object and return it - switch (fieldType) - { - case SERIALIZATION_TYPE_TAGGED_OBJECT: - *pType = g_pObjectClass->GetManagedClassObject(); - FALLTHROUGH; - case SERIALIZATION_TYPE_TYPE: - case SERIALIZATION_TYPE_STRING: - *value = ArgSlotToObj(GetDataFromBlob( - pCtorAssembly, fieldType, nullTH, &pBlob, pBlobEnd, pModule, &bObjectCreated)); - _ASSERTE(bObjectCreated || *value == NULL); - - if (*value == NULL) - { - // load the proper type so that code in managed knows which property to load - if (fieldType == SERIALIZATION_TYPE_STRING) - *pType = CoreLibBinder::GetElementType(ELEMENT_TYPE_STRING)->GetManagedClassObject(); - else if (fieldType == SERIALIZATION_TYPE_TYPE) - *pType = CoreLibBinder::GetClass(CLASS__TYPE)->GetManagedClassObject(); - } - break; - case SERIALIZATION_TYPE_SZARRAY: + if (gc.Value == NULL) { - *value = NULL; - int arraySize = (int)GetDataFromBlob(pCtorAssembly, SERIALIZATION_TYPE_I4, nullTH, &pBlob, pBlobEnd, pModule, &bObjectCreated); + // load the proper type so that code in managed knows which property to load + if (fieldType == SERIALIZATION_TYPE_STRING) + gc.Type = CoreLibBinder::GetElementType(ELEMENT_TYPE_STRING)->GetManagedClassObject(); + else if (fieldType == SERIALIZATION_TYPE_TYPE) + gc.Type = CoreLibBinder::GetClass(CLASS__TYPE)->GetManagedClassObject(); + } + break; + case SERIALIZATION_TYPE_SZARRAY: + { + gc.Value = NULL; + int arraySize = (int)GetDataFromBlob(pCtorAssembly, SERIALIZATION_TYPE_I4, nullTH, &pBlob, pBlobEnd, pModule, &bObjectCreated); - if (arraySize != -1) + if (arraySize != -1) + { + _ASSERTE(!bObjectCreated); + if (arrayType == SERIALIZATION_TYPE_STRING) + nullTH = TypeHandle(CoreLibBinder::GetElementType(ELEMENT_TYPE_STRING)); + else if (arrayType == SERIALIZATION_TYPE_TYPE) + nullTH = TypeHandle(CoreLibBinder::GetClass(CLASS__TYPE)); + else if (arrayType == SERIALIZATION_TYPE_TAGGED_OBJECT) + nullTH = TypeHandle(g_pObjectClass); + ReadArray(pCtorAssembly, arrayType, arraySize, nullTH, &pBlob, pBlobEnd, pModule, (BASEARRAYREF*)&gc.Value); + } + if (gc.Value == NULL) + { + TypeHandle arrayTH; + switch (arrayType) { - _ASSERTE(!bObjectCreated); - if (arrayType == SERIALIZATION_TYPE_STRING) - nullTH = TypeHandle(CoreLibBinder::GetElementType(ELEMENT_TYPE_STRING)); - else if (arrayType == SERIALIZATION_TYPE_TYPE) - nullTH = TypeHandle(CoreLibBinder::GetClass(CLASS__TYPE)); - else if (arrayType == SERIALIZATION_TYPE_TAGGED_OBJECT) - nullTH = TypeHandle(g_pObjectClass); - ReadArray(pCtorAssembly, arrayType, arraySize, nullTH, &pBlob, pBlobEnd, pModule, (BASEARRAYREF*)value); + case SERIALIZATION_TYPE_STRING: + arrayTH = TypeHandle(CoreLibBinder::GetElementType(ELEMENT_TYPE_STRING)); + break; + case SERIALIZATION_TYPE_TYPE: + arrayTH = TypeHandle(CoreLibBinder::GetClass(CLASS__TYPE)); + break; + case SERIALIZATION_TYPE_TAGGED_OBJECT: + arrayTH = TypeHandle(g_pObjectClass); + break; + default: + if (SERIALIZATION_TYPE_BOOLEAN <= arrayType && arrayType <= SERIALIZATION_TYPE_R8) + arrayTH = TypeHandle(CoreLibBinder::GetElementType((CorElementType)arrayType)); } - if (*value == NULL) + if (!arrayTH.IsNull()) { - TypeHandle arrayTH; - switch (arrayType) - { - case SERIALIZATION_TYPE_STRING: - arrayTH = TypeHandle(CoreLibBinder::GetElementType(ELEMENT_TYPE_STRING)); - break; - case SERIALIZATION_TYPE_TYPE: - arrayTH = TypeHandle(CoreLibBinder::GetClass(CLASS__TYPE)); - break; - case SERIALIZATION_TYPE_TAGGED_OBJECT: - arrayTH = TypeHandle(g_pObjectClass); - break; - default: - if (SERIALIZATION_TYPE_BOOLEAN <= arrayType && arrayType <= SERIALIZATION_TYPE_R8) - arrayTH = TypeHandle(CoreLibBinder::GetElementType((CorElementType)arrayType)); - } - if (!arrayTH.IsNull()) - { - arrayTH = ClassLoader::LoadArrayTypeThrowing(arrayTH); - *pType = arrayTH.GetManagedClassObject(); - } + arrayTH = ClassLoader::LoadArrayTypeThrowing(arrayTH); + gc.Type = arrayTH.GetManagedClassObject(); } - break; } - default: - if (SERIALIZATION_TYPE_BOOLEAN <= fieldType && fieldType <= SERIALIZATION_TYPE_R8) - pMTValue = CoreLibBinder::GetElementType((CorElementType)fieldType); - else if(fieldType == SERIALIZATION_TYPE_ENUM) - fieldType = (CorSerializationType)pMTValue->GetInternalCorElementType(); - else - COMPlusThrow(kCustomAttributeFormatException); - - ARG_SLOT val = GetDataFromBlob(pCtorAssembly, fieldType, nullTH, &pBlob, pBlobEnd, pModule, &bObjectCreated); - _ASSERTE(!bObjectCreated); - - *value = pMTValue->Box((void*)ArgSlotEndiannessFixup(&val, pMTValue->GetNumInstanceFieldBytes())); + break; } + default: + if (SERIALIZATION_TYPE_BOOLEAN <= fieldType && fieldType <= SERIALIZATION_TYPE_R8) + pMTValue = CoreLibBinder::GetElementType((CorElementType)fieldType); + else if(fieldType == SERIALIZATION_TYPE_ENUM) + fieldType = (CorSerializationType)pMTValue->GetInternalCorElementType(); + else + COMPlusThrow(kCustomAttributeFormatException); + + ARG_SLOT val = GetDataFromBlob(pCtorAssembly, fieldType, nullTH, &pBlob, pBlobEnd, pModule, &bObjectCreated); + _ASSERTE(!bObjectCreated); - *ppBlobStart = pBlob; + gc.Value = pMTValue->Box((void*)ArgSlotEndiannessFixup(&val, pMTValue->GetNumInstanceFieldBytes())); } - HELPER_METHOD_FRAME_END(); + + *ppBlobStart = pBlob; + pName.Set(gc.Name); + pType.Set(gc.Type); + pValue.Set(gc.Value); + + GCPROTECT_END(); + END_QCALL; } -FCIMPLEND /*static*/ TypeHandle COMCustomAttribute::GetTypeHandleFromBlob(Assembly *pCtorAssembly, diff --git a/src/coreclr/vm/customattribute.h b/src/coreclr/vm/customattribute.h index 10be7f36ebb752..3c5fb7b6e5f62d 100644 --- a/src/coreclr/vm/customattribute.h +++ b/src/coreclr/vm/customattribute.h @@ -24,53 +24,22 @@ class Attribute DomainAssembly* pDomainAssembly); }; -class COMCustomAttribute -{ -public: - - // custom attributes utility functions - static FCDECL6(LPVOID, CreateCaObject, ReflectModuleBaseObject* pAttributedModuleUNSAFE, ReflectClassBaseObject* pCaTypeUNSAFE, ReflectMethodObject *pMethodUNSAFE, BYTE** ppBlob, BYTE* pEndBlob, INT32* pcNamedArgs); - static FCDECL7(void, GetPropertyOrFieldData, ReflectModuleBaseObject *pModuleUNSAFE, BYTE** ppBlobStart, BYTE* pBlobEnd, STRINGREF* pName, CLR_BOOL* pbIsProperty, OBJECTREF* pType, OBJECTREF* value); - -private: - - static TypeHandle GetTypeHandleFromBlob( - Assembly *pCtorAssembly, - CorSerializationType objType, - BYTE **pBlob, - const BYTE *endBlob, - Module *pModule); - - static ARG_SLOT GetDataFromBlob( - Assembly *pCtorAssembly, - CorSerializationType type, - TypeHandle th, - BYTE **pBlob, - const BYTE *endBlob, - Module *pModule, - BOOL *bObjectCreated); - - static void ReadArray( - Assembly *pCtorAssembly, - CorSerializationType arrayType, - int size, - TypeHandle th, - BYTE **pBlob, - const BYTE *endBlob, - Module *pModule, - BASEARRAYREF *pArray); - - static int GetStringSize( - BYTE **pBlob, - const BYTE *endBlob); - - template < typename T > - static BOOL CopyArrayVAL( - BASEARRAYREF pArray, - int nElements, - BYTE **pBlob, - const BYTE *endBlob); -}; - +extern "C" void QCALLTYPE CustomAttribute_CreateCustomAttributeInstance( + QCall::ObjectHandleOnStack pAttributedModule, + QCall::ObjectHandleOnStack pCaType, + QCall::ObjectHandleOnStack pMethod, + BYTE** ppBlob, + BYTE* pEndBlob, + INT32* pcNamedArgs, + QCall::ObjectHandleOnStack result); + +extern "C" void QCALLTYPE CustomAttribute_CreatePropertyOrFieldData( + QCall::ObjectHandleOnStack pModule, + BYTE** ppBlobStart, + BYTE* pBlobEnd, + QCall::ObjectHandleOnStack pName, + bool* pbIsProperty, + QCall::ObjectHandleOnStack pType, + QCall::ObjectHandleOnStack value); #endif diff --git a/src/coreclr/vm/ecalllist.h b/src/coreclr/vm/ecalllist.h index 4e7942c93b2dd9..0da65ef49f38a8 100644 --- a/src/coreclr/vm/ecalllist.h +++ b/src/coreclr/vm/ecalllist.h @@ -244,11 +244,6 @@ FCFuncStart(gCOMModuleHandleFuncs) FCFuncElement("GetMDStreamVersion", ModuleHandle::GetMDStreamVersion) FCFuncEnd() -FCFuncStart(gCOMCustomAttributeFuncs) - FCFuncElement("_CreateCaObject", COMCustomAttribute::CreateCaObject) - FCFuncElement("_GetPropertyOrFieldData", COMCustomAttribute::GetPropertyOrFieldData) -FCFuncEnd() - FCFuncStart(gRuntimeAssemblyFuncs) FCFuncElement("FCallIsDynamic", AssemblyNative::IsDynamic) FCFuncElement("GetManifestModule", AssemblyHandle::GetManifestModule) @@ -559,7 +554,6 @@ FCClassElement("AssemblyLoadContext", "System.Runtime.Loader", gAssemblyLoadCont FCClassElement("Buffer", "System", gBufferFuncs) FCClassElement("CastHelpers", "System.Runtime.CompilerServices", gCastHelpers) FCClassElement("ComAwareWeakReference", "System", gComAwareWeakReferenceFuncs) -FCClassElement("CustomAttribute", "System.Reflection", gCOMCustomAttributeFuncs) FCClassElement("Debugger", "System.Diagnostics", gDiagnosticsDebugger) FCClassElement("Delegate", "System", gDelegateFuncs) FCClassElement("DependentHandle", "System.Runtime", gDependentHandleFuncs) diff --git a/src/coreclr/vm/qcallentrypoints.cpp b/src/coreclr/vm/qcallentrypoints.cpp index 8ff379f40f6e08..ca8dda9fef878e 100644 --- a/src/coreclr/vm/qcallentrypoints.cpp +++ b/src/coreclr/vm/qcallentrypoints.cpp @@ -81,6 +81,8 @@ static const Entry s_QCall[] = DllImportEntry(ArgIterator_GetNextArgType) DllImportEntry(ArgIterator_GetNextArg) DllImportEntry(ArgIterator_GetNextArg2) + DllImportEntry(CustomAttribute_CreateCustomAttributeInstance) + DllImportEntry(CustomAttribute_CreatePropertyOrFieldData) DllImportEntry(Enum_GetValuesAndNames) DllImportEntry(DebugDebugger_Launch) DllImportEntry(DebugDebugger_Log) From 49fc4aef25c7d266f14817fe4f4bc9d32e26b43f Mon Sep 17 00:00:00 2001 From: Aaron R Robinson Date: Thu, 21 Mar 2024 19:34:52 -0700 Subject: [PATCH 3/7] Convert functions in customattribute.h into QCalls --- .../Reflection/RuntimeCustomAttributeData.cs | 14 +- src/coreclr/vm/callconvbuilder.cpp | 4 +- src/coreclr/vm/customattribute.cpp | 1334 ++++++++--------- src/coreclr/vm/customattribute.h | 17 +- 4 files changed, 675 insertions(+), 694 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttributeData.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttributeData.cs index b51ce3fe77cb8a..618e9b7f6b4668 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttributeData.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttributeData.cs @@ -1894,7 +1894,7 @@ internal static object[] CreateAttributeArrayHelper(RuntimeType caType, int elem [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "CustomAttribute_CreateCustomAttributeInstance")] private static partial void CreateCustomAttributeInstance( - ObjectHandleOnStack pModule, + QCallModule pModule, ObjectHandleOnStack type, ObjectHandleOnStack pCtor, ref IntPtr ppBlob, @@ -1911,7 +1911,7 @@ private static object CreateCustomAttributeInstance(RuntimeModule module, Runtim object? result = null; CreateCustomAttributeInstance( - ObjectHandleOnStack.Create(ref module), + new QCallModule(ref module), ObjectHandleOnStack.Create(ref type), ObjectHandleOnStack.Create(ref ctor), ref blob, @@ -1921,12 +1921,12 @@ private static object CreateCustomAttributeInstance(RuntimeModule module, Runtim return result!; } - [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "CustomAttribute_CreateCustomAttributeInstance", StringMarshalling = StringMarshalling.Utf16)] + [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "CustomAttribute_CreatePropertyOrFieldData", StringMarshalling = StringMarshalling.Utf16)] private static partial void CreatePropertyOrFieldData( - ObjectHandleOnStack pModule, + QCallModule pModule, ref IntPtr ppBlobStart, IntPtr pBlobEnd, - ObjectHandleOnStack name, + StringHandleOnStack name, [MarshalAs(UnmanagedType.U1)] out bool bIsProperty, ObjectHandleOnStack type, ObjectHandleOnStack value); @@ -1943,10 +1943,10 @@ private static void GetPropertyOrFieldData( RuntimeType? typeLocal = null; object? valueLocal = null; CreatePropertyOrFieldData( - ObjectHandleOnStack.Create(ref module), + new QCallModule(ref module), ref blobStart, blobEnd, - ObjectHandleOnStack.Create(ref nameLocal), + new StringHandleOnStack(ref nameLocal), out isProperty, ObjectHandleOnStack.Create(ref typeLocal), ObjectHandleOnStack.Create(ref valueLocal)); diff --git a/src/coreclr/vm/callconvbuilder.cpp b/src/coreclr/vm/callconvbuilder.cpp index 3075087ee7b836..7303cd960fa104 100644 --- a/src/coreclr/vm/callconvbuilder.cpp +++ b/src/coreclr/vm/callconvbuilder.cpp @@ -453,7 +453,7 @@ HRESULT CallConv::TryGetCallingConventionFromUnmanagedCallConv( InlineFactory, 4> caValueArrayFactory; DomainAssembly* domainAssembly = pMD->GetLoaderModule()->GetDomainAssembly(); - IfFailThrow(Attribute::ParseAttributeArgumentValues( + IfFailThrow(Attribute::ParseArgumentValues( pData, cData, &caValueArrayFactory, @@ -528,7 +528,7 @@ bool CallConv::TryGetCallingConventionFromUnmanagedCallersOnly(_In_ MethodDesc* InlineFactory, 4> caValueArrayFactory; DomainAssembly* domainAssembly = pMD->GetLoaderModule()->GetDomainAssembly(); - IfFailThrow(Attribute::ParseAttributeArgumentValues( + IfFailThrow(Attribute::ParseArgumentValues( pData, cData, &caValueArrayFactory, diff --git a/src/coreclr/vm/customattribute.cpp b/src/coreclr/vm/customattribute.cpp index b612a3373890c2..e5839d1c2993f7 100644 --- a/src/coreclr/vm/customattribute.cpp +++ b/src/coreclr/vm/customattribute.cpp @@ -326,8 +326,7 @@ static HRESULT ParseCaNamedArgs( return hr; } -/*static*/ -HRESULT Attribute::ParseAttributeArgumentValues( +HRESULT Attribute::ParseArgumentValues( void* pCa, INT32 cCa, CaValueArrayFactory* pCaValueArrayFactory, @@ -349,820 +348,803 @@ HRESULT Attribute::ParseAttributeArgumentValues( return hr; } -extern "C" void QCALLTYPE CustomAttribute_CreateCustomAttributeInstance( - QCall::ObjectHandleOnStack pAttributedModule, - QCall::ObjectHandleOnStack pCaType, - QCall::ObjectHandleOnStack pMethod, - BYTE** ppBlob, - BYTE* pEndBlob, - INT32* pcNamedArgs, - QCall::ObjectHandleOnStack result) +// retrieve the string size in a CA blob. Advance the blob pointer to point to +// the beginning of the string immediately following the size +static int GetStringSize(BYTE **pBlob, const BYTE *endBlob) { - QCALL_CONTRACT; + STANDARD_VM_CONTRACT; - BEGIN_QCALL; + if (*pBlob >= endBlob ) + { // No buffer at all, or buffer overrun + COMPlusThrow(kCustomAttributeFormatException); + } - GCX_COOP(); + if (**pBlob == 0xFF) + { // Special case null string. + ++(*pBlob); + return -1; + } - struct - { - REFLECTCLASSBASEREF refCaType; - OBJECTREF ca; - REFLECTMETHODREF refCtor; - REFLECTMODULEBASEREF refAttributedModule; - } gc; - gc.refCaType = NULL; - gc.ca = NULL; - gc.refCtor = NULL; - gc.refAttributedModule = NULL; - GCPROTECT_BEGIN(gc); + ULONG ulSize; + if (FAILED(CPackedLen::SafeGetData((BYTE const *)*pBlob, (BYTE const *)endBlob, (ULONG *)&ulSize, (BYTE const **)pBlob))) { - gc.refCaType = (REFLECTCLASSBASEREF)pCaType.Get(); - gc.refCtor = (REFLECTMETHODREF)pMethod.Get(); - gc.refAttributedModule = (REFLECTMODULEBASEREF)pAttributedModule.Get(); - - MethodDesc* pCtorMD = gc.refCtor->GetMethod(); - TypeHandle th = gc.refCaType->GetType(); - - MethodDescCallSite ctorCallSite(pCtorMD, th); - MetaSig* pSig = ctorCallSite.GetMetaSig(); - BYTE* pBlob = *ppBlob; + COMPlusThrow(kCustomAttributeFormatException); + } - // get the number of arguments and allocate an array for the args - ARG_SLOT *args = NULL; - UINT cArgs = pSig->NumFixedArgs() + 1; // make room for the this pointer - UINT i = 1; // used to flag that we actually get the right number of arg from the blob + return (int)ulSize; +} - args = (ARG_SLOT*)_alloca(cArgs * sizeof(ARG_SLOT)); - memset((void*)args, 0, cArgs * sizeof(ARG_SLOT)); +// Forward declaration +static ARG_SLOT GetDataFromBlob(Assembly *pCtorAssembly, + CorSerializationType type, + TypeHandle th, + BYTE **pBlob, + const BYTE *endBlob, + Module *pModule, + BOOL *bObjectCreated); - OBJECTREF *argToProtect = (OBJECTREF*)_alloca(cArgs * sizeof(OBJECTREF)); - memset((void*)argToProtect, 0, cArgs * sizeof(OBJECTREF)); +static TypeHandle GetTypeHandleFromBlob(Assembly *pCtorAssembly, + CorSerializationType objType, + BYTE **pBlob, + const BYTE *endBlob, + Module *pModule) +{ + STANDARD_VM_CONTRACT; - // load the this pointer - argToProtect[0] = gc.refCaType->GetType().GetMethodTable()->Allocate(); // this is the value to return after the ctor invocation + // we must box which means we must get the method table, switch again on the element type + MethodTable *pMTType = NULL; + TypeHandle nullTH; + TypeHandle RtnTypeHnd; - if (pBlob) - { - if (pBlob < pEndBlob) - { - if (pBlob + 2 > pEndBlob) - { - COMPlusThrow(kCustomAttributeFormatException); - } - INT16 prolog = GET_UNALIGNED_VAL16(pBlob); - if (prolog != 1) - COMPlusThrow(kCustomAttributeFormatException); - pBlob += 2; - } + switch ((DWORD)objType) { + case SERIALIZATION_TYPE_BOOLEAN: + case SERIALIZATION_TYPE_I1: + case SERIALIZATION_TYPE_U1: + case SERIALIZATION_TYPE_CHAR: + case SERIALIZATION_TYPE_I2: + case SERIALIZATION_TYPE_U2: + case SERIALIZATION_TYPE_I4: + case SERIALIZATION_TYPE_U4: + case SERIALIZATION_TYPE_R4: + case SERIALIZATION_TYPE_I8: + case SERIALIZATION_TYPE_U8: + case SERIALIZATION_TYPE_R8: + case SERIALIZATION_TYPE_STRING: + pMTType = CoreLibBinder::GetElementType((CorElementType)objType); + RtnTypeHnd = TypeHandle(pMTType); + break; - if (cArgs > 1) - { - GCPROTECT_ARRAY_BEGIN(*argToProtect, cArgs); - { - // loop through the args - for (i = 1; i < cArgs; i++) { - CorElementType type = pSig->NextArg(); - if (type == ELEMENT_TYPE_END) - break; - BOOL bObjectCreated = FALSE; - TypeHandle th = pSig->GetLastTypeHandleThrowing(); - if (th.IsArray()) - // get the array element - th = th.GetArrayElementTypeHandle(); - ARG_SLOT data = COMCustomAttribute::GetDataFromBlob(pCtorMD->GetAssembly(), (CorSerializationType)type, th, &pBlob, pEndBlob, gc.refAttributedModule->GetModule(), &bObjectCreated); - if (bObjectCreated) - argToProtect[i] = ArgSlotToObj(data); - else - args[i] = data; - } - } - GCPROTECT_END(); + case ELEMENT_TYPE_CLASS: + pMTType = CoreLibBinder::GetClass(CLASS__TYPE); + RtnTypeHnd = TypeHandle(pMTType); + break; - // We have borrowed the signature from MethodDescCallSite. We have to put it back into the initial position - // because of that's where MethodDescCallSite expects to find it below. - pSig->Reset(); + case SERIALIZATION_TYPE_TAGGED_OBJECT: + pMTType = g_pObjectClass; + RtnTypeHnd = TypeHandle(pMTType); + break; - for (i = 1; i < cArgs; i++) - { - if (argToProtect[i] != NULL) - { - _ASSERTE(args[i] == NULL); - args[i] = ObjToArgSlot(argToProtect[i]); - } - } - } - } - args[0] = ObjToArgSlot(argToProtect[0]); + case SERIALIZATION_TYPE_TYPE: + { + int size = GetStringSize(pBlob, endBlob); + if (size == -1) + return nullTH; - if (i != cArgs) + if ((size+1 <= 1) || (size > endBlob - *pBlob)) COMPlusThrow(kCustomAttributeFormatException); - // check if there are any named properties to invoke, - // if so set the by ref int passed in to point - // to the blob position where name properties start - *pcNamedArgs = 0; - - if (pBlob && pBlob != pEndBlob) - { - if (pBlob + 2 > pEndBlob) - COMPlusThrow(kCustomAttributeFormatException); + LPUTF8 szName = (LPUTF8)_alloca(size + 1); + memcpy(szName, *pBlob, size); + *pBlob += size; + szName[size] = 0; - *pcNamedArgs = GET_UNALIGNED_VAL16(pBlob); + RtnTypeHnd = TypeName::GetTypeReferencedByCustomAttribute(szName, pModule->GetAssembly()); + break; + } - pBlob += 2; + case SERIALIZATION_TYPE_ENUM: + { + // get the enum type + BOOL isObject = FALSE; + ReflectClassBaseObject *pType = (ReflectClassBaseObject*)OBJECTREFToObject(ArgSlotToObj(GetDataFromBlob(pCtorAssembly, + SERIALIZATION_TYPE_TYPE, + nullTH, + pBlob, + endBlob, + pModule, + &isObject))); + if (pType != NULL) + { + _ASSERTE(isObject); + RtnTypeHnd = pType->GetType(); + _ASSERTE((objType == SERIALIZATION_TYPE_ENUM) ? RtnTypeHnd.GetMethodTable()->IsEnum() : TRUE); } + else + { + RtnTypeHnd = TypeHandle(); + } + break; + } - *ppBlob = pBlob; - - if (*pcNamedArgs == 0 && pBlob != pEndBlob) - COMPlusThrow(kCustomAttributeFormatException); - - // make the invocation to the ctor - gc.ca = ArgSlotToObj(args[0]); - if (pCtorMD->GetMethodTable()->IsValueType()) - args[0] = PtrToArgSlot(OBJECTREFToObject(gc.ca)->UnBox()); + default: + COMPlusThrow(kCustomAttributeFormatException); + } - ctorCallSite.CallWithValueTypes(args); + return RtnTypeHnd; +} - result.Set(gc.ca); +// copy the values of an array of integers from a CA blob +// (i.e., always stored in little-endian, and needs not be aligned). +// Returns TRUE on success, FALSE if the blob was not big enough. +// Advances *pBlob by the amount copied. +template +static BOOL CopyArrayVAL(BASEARRAYREF pArray, int nElements, BYTE **pBlob, const BYTE *endBlob) +{ + int sizeData; // = size * 2; with integer overflow check + if (!ClrSafeInt::multiply(nElements, sizeof(T), sizeData)) + return FALSE; + if (sizeData > endBlob - *pBlob) // integer overflow check + return FALSE; +#if BIGENDIAN + T *ptDest = reinterpret_cast(pArray->GetDataPtr()); + for (int iElement = 0; iElement < nElements; iElement++) + { + T tValue; + BYTE *pbSrc = *pBlob + iElement * sizeof(T); + BYTE *pbDest = reinterpret_cast(&tValue); + for (size_t iByte = 0; iByte < sizeof(T); iByte++) + { + pbDest[sizeof(T) - 1 - iByte] = pbSrc[iByte]; + } + ptDest[iElement] = tValue; } - GCPROTECT_END(); - END_QCALL; +#else // BIGENDIAN + memcpyNoGCRefs(pArray->GetDataPtr(), *pBlob, sizeData); +#endif // BIGENDIAN + *pBlob += sizeData; + return TRUE; } -extern "C" void QCALLTYPE CustomAttribute_CreatePropertyOrFieldData( - QCall::ObjectHandleOnStack pModuleObj, - BYTE** ppBlobStart, - BYTE* pBlobEnd, - QCall::ObjectHandleOnStack pName, - bool* pbIsProperty, - QCall::ObjectHandleOnStack pType, - QCall::ObjectHandleOnStack pValue) +// read the whole array as a chunk +static void ReadArray(Assembly *pCtorAssembly, + CorSerializationType arrayType, + int size, + TypeHandle th, + BYTE **pBlob, + const BYTE *endBlob, + Module *pModule, + BASEARRAYREF *pArray) { - QCALL_CONTRACT; - - BEGIN_QCALL; + STANDARD_VM_CONTRACT; - BYTE* pBlob = *ppBlobStart; - - GCX_COOP(); + ARG_SLOT element = 0; - struct - { - OBJECTREF Name; - OBJECTREF Type; - OBJECTREF Value; - } gc; - gc.Name = NULL; - gc.Type = NULL; - gc.Value = NULL; - GCPROTECT_BEGIN(gc); - - Module *pModule = pModuleObj.Get()->GetModule(); - - Assembly *pCtorAssembly = NULL; - - MethodTable *pMTValue = NULL; - CorSerializationType arrayType = SERIALIZATION_TYPE_BOOLEAN; - BOOL bObjectCreated = FALSE; - TypeHandle nullTH; - - if (pBlob + 2 > pBlobEnd) - COMPlusThrow(kCustomAttributeFormatException); - - // get whether it is a field or a property - CorSerializationType propOrField = (CorSerializationType)*pBlob; - pBlob++; - if (propOrField == SERIALIZATION_TYPE_FIELD) - *pbIsProperty = FALSE; - else if (propOrField == SERIALIZATION_TYPE_PROPERTY) - *pbIsProperty = TRUE; - else - COMPlusThrow(kCustomAttributeFormatException); + switch ((DWORD)arrayType) { + case SERIALIZATION_TYPE_BOOLEAN: + case SERIALIZATION_TYPE_I1: + case SERIALIZATION_TYPE_U1: + *pArray = (BASEARRAYREF)AllocatePrimitiveArray((CorElementType)arrayType, size); + if (!CopyArrayVAL(*pArray, size, pBlob, endBlob)) + goto badBlob; + break; - // get the type of the field - CorSerializationType fieldType = (CorSerializationType)*pBlob; - pBlob++; - if (fieldType == SERIALIZATION_TYPE_SZARRAY) + case SERIALIZATION_TYPE_CHAR: + case SERIALIZATION_TYPE_I2: + case SERIALIZATION_TYPE_U2: { - arrayType = (CorSerializationType)*pBlob; - - if (pBlob + 1 > pBlobEnd) - COMPlusThrow(kCustomAttributeFormatException); - - pBlob++; + *pArray = (BASEARRAYREF)AllocatePrimitiveArray((CorElementType)arrayType, size); + if (!CopyArrayVAL(*pArray, size, pBlob, endBlob)) + goto badBlob; + break; } - if (fieldType == SERIALIZATION_TYPE_ENUM || arrayType == SERIALIZATION_TYPE_ENUM) + case SERIALIZATION_TYPE_I4: + case SERIALIZATION_TYPE_U4: + case SERIALIZATION_TYPE_R4: { - // get the enum type - ReflectClassBaseObject *pEnum = - (ReflectClassBaseObject*)OBJECTREFToObject(ArgSlotToObj(GetDataFromBlob( - pCtorAssembly, SERIALIZATION_TYPE_TYPE, nullTH, &pBlob, pBlobEnd, pModule, &bObjectCreated))); - - if (pEnum == NULL) - COMPlusThrow(kCustomAttributeFormatException); - - _ASSERTE(bObjectCreated); + *pArray = (BASEARRAYREF)AllocatePrimitiveArray((CorElementType)arrayType, size); + if (!CopyArrayVAL(*pArray, size, pBlob, endBlob)) + goto badBlob; + break; + } + case SERIALIZATION_TYPE_I8: + case SERIALIZATION_TYPE_U8: + case SERIALIZATION_TYPE_R8: + { + *pArray = (BASEARRAYREF)AllocatePrimitiveArray((CorElementType)arrayType, size); + if (!CopyArrayVAL(*pArray, size, pBlob, endBlob)) + goto badBlob; + break; + } + case ELEMENT_TYPE_CLASS: + case SERIALIZATION_TYPE_TYPE: + case SERIALIZATION_TYPE_STRING: + case SERIALIZATION_TYPE_SZARRAY: + case SERIALIZATION_TYPE_TAGGED_OBJECT: + { + BOOL isObject; - TypeHandle th = pEnum->GetType(); - _ASSERTE(th.IsEnum()); + // If we haven't figured out the type of the array, throw bad blob exception + if (th.IsNull()) + goto badBlob; - pMTValue = th.AsMethodTable(); - if (fieldType == SERIALIZATION_TYPE_ENUM) - // load the enum type to pass it back - gc.Type = th.GetManagedClassObject(); - else - nullTH = th; + *pArray = (BASEARRAYREF)AllocateObjectArray(size, th); + if (arrayType == SERIALIZATION_TYPE_SZARRAY) + // switch the th to be the proper one + th = th.GetArrayElementTypeHandle(); + for (int i = 0; i < size; i++) { + element = GetDataFromBlob(pCtorAssembly, arrayType, th, pBlob, endBlob, pModule, &isObject); + _ASSERTE(isObject || element == NULL); + ((PTRARRAYREF)(*pArray))->SetAt(i, ArgSlotToObj(element)); + } + break; } - // get the string representing the field/property name - gc.Name = ArgSlotToString(GetDataFromBlob( - pCtorAssembly, SERIALIZATION_TYPE_STRING, nullTH, &pBlob, pBlobEnd, pModule, &bObjectCreated)); - _ASSERTE(bObjectCreated || gc.Name == NULL); - - // create the object and return it - switch (fieldType) + case SERIALIZATION_TYPE_ENUM: { - case SERIALIZATION_TYPE_TAGGED_OBJECT: - gc.Type = g_pObjectClass->GetManagedClassObject(); - FALLTHROUGH; - case SERIALIZATION_TYPE_TYPE: - case SERIALIZATION_TYPE_STRING: - gc.Value = ArgSlotToObj(GetDataFromBlob( - pCtorAssembly, fieldType, nullTH, &pBlob, pBlobEnd, pModule, &bObjectCreated)); - _ASSERTE(bObjectCreated || gc.Value == NULL); + INT32 bounds = size; - if (gc.Value == NULL) - { - // load the proper type so that code in managed knows which property to load - if (fieldType == SERIALIZATION_TYPE_STRING) - gc.Type = CoreLibBinder::GetElementType(ELEMENT_TYPE_STRING)->GetManagedClassObject(); - else if (fieldType == SERIALIZATION_TYPE_TYPE) - gc.Type = CoreLibBinder::GetClass(CLASS__TYPE)->GetManagedClassObject(); - } - break; - case SERIALIZATION_TYPE_SZARRAY: - { - gc.Value = NULL; - int arraySize = (int)GetDataFromBlob(pCtorAssembly, SERIALIZATION_TYPE_I4, nullTH, &pBlob, pBlobEnd, pModule, &bObjectCreated); + // If we haven't figured out the type of the array, throw bad blob exception + if (th.IsNull()) + goto badBlob; - if (arraySize != -1) - { - _ASSERTE(!bObjectCreated); - if (arrayType == SERIALIZATION_TYPE_STRING) - nullTH = TypeHandle(CoreLibBinder::GetElementType(ELEMENT_TYPE_STRING)); - else if (arrayType == SERIALIZATION_TYPE_TYPE) - nullTH = TypeHandle(CoreLibBinder::GetClass(CLASS__TYPE)); - else if (arrayType == SERIALIZATION_TYPE_TAGGED_OBJECT) - nullTH = TypeHandle(g_pObjectClass); - ReadArray(pCtorAssembly, arrayType, arraySize, nullTH, &pBlob, pBlobEnd, pModule, (BASEARRAYREF*)&gc.Value); - } - if (gc.Value == NULL) - { - TypeHandle arrayTH; - switch (arrayType) - { - case SERIALIZATION_TYPE_STRING: - arrayTH = TypeHandle(CoreLibBinder::GetElementType(ELEMENT_TYPE_STRING)); - break; - case SERIALIZATION_TYPE_TYPE: - arrayTH = TypeHandle(CoreLibBinder::GetClass(CLASS__TYPE)); - break; - case SERIALIZATION_TYPE_TAGGED_OBJECT: - arrayTH = TypeHandle(g_pObjectClass); - break; - default: - if (SERIALIZATION_TYPE_BOOLEAN <= arrayType && arrayType <= SERIALIZATION_TYPE_R8) - arrayTH = TypeHandle(CoreLibBinder::GetElementType((CorElementType)arrayType)); - } - if (!arrayTH.IsNull()) - { - arrayTH = ClassLoader::LoadArrayTypeThrowing(arrayTH); - gc.Type = arrayTH.GetManagedClassObject(); - } - } + unsigned elementSize = th.GetSize(); + TypeHandle arrayHandle = ClassLoader::LoadArrayTypeThrowing(th); + if (arrayHandle.IsNull()) + goto badBlob; + *pArray = (BASEARRAYREF)AllocateSzArray(arrayHandle, bounds); + BOOL fSuccess; + switch (elementSize) + { + case 1: + fSuccess = CopyArrayVAL(*pArray, size, pBlob, endBlob); + break; + case 2: + fSuccess = CopyArrayVAL(*pArray, size, pBlob, endBlob); + break; + case 4: + fSuccess = CopyArrayVAL(*pArray, size, pBlob, endBlob); + break; + case 8: + fSuccess = CopyArrayVAL(*pArray, size, pBlob, endBlob); break; - } default: - if (SERIALIZATION_TYPE_BOOLEAN <= fieldType && fieldType <= SERIALIZATION_TYPE_R8) - pMTValue = CoreLibBinder::GetElementType((CorElementType)fieldType); - else if(fieldType == SERIALIZATION_TYPE_ENUM) - fieldType = (CorSerializationType)pMTValue->GetInternalCorElementType(); - else - COMPlusThrow(kCustomAttributeFormatException); - - ARG_SLOT val = GetDataFromBlob(pCtorAssembly, fieldType, nullTH, &pBlob, pBlobEnd, pModule, &bObjectCreated); - _ASSERTE(!bObjectCreated); - - gc.Value = pMTValue->Box((void*)ArgSlotEndiannessFixup(&val, pMTValue->GetNumInstanceFieldBytes())); + fSuccess = FALSE; + } + if (!fSuccess) + goto badBlob; + break; } - *ppBlobStart = pBlob; - pName.Set(gc.Name); - pType.Set(gc.Type); - pValue.Set(gc.Value); + default: + badBlob: + COMPlusThrow(kCustomAttributeFormatException); + } - GCPROTECT_END(); - END_QCALL; } -/*static*/ -TypeHandle COMCustomAttribute::GetTypeHandleFromBlob(Assembly *pCtorAssembly, - CorSerializationType objType, - BYTE **pBlob, - const BYTE *endBlob, - Module *pModule) +// get data out of the blob according to a CorElementType +static ARG_SLOT GetDataFromBlob(Assembly *pCtorAssembly, + CorSerializationType type, + TypeHandle th, + BYTE **pBlob, + const BYTE *endBlob, + Module *pModule, + BOOL *bObjectCreated) { - CONTRACTL - { - THROWS; - } - CONTRACTL_END; + STANDARD_VM_CONTRACT; - // we must box which means we must get the method table, switch again on the element type - MethodTable *pMTType = NULL; + ARG_SLOT retValue = 0; + *bObjectCreated = FALSE; TypeHandle nullTH; - TypeHandle RtnTypeHnd; + TypeHandle typeHnd; + + switch ((DWORD)type) { - switch ((DWORD)objType) { case SERIALIZATION_TYPE_BOOLEAN: case SERIALIZATION_TYPE_I1: case SERIALIZATION_TYPE_U1: + if (*pBlob + 1 <= endBlob) { + retValue = (ARG_SLOT)**pBlob; + *pBlob += 1; + break; + } + goto badBlob; + case SERIALIZATION_TYPE_CHAR: case SERIALIZATION_TYPE_I2: case SERIALIZATION_TYPE_U2: + if (*pBlob + 2 <= endBlob) { + retValue = (ARG_SLOT)GET_UNALIGNED_VAL16(*pBlob); + *pBlob += 2; + break; + } + goto badBlob; + case SERIALIZATION_TYPE_I4: case SERIALIZATION_TYPE_U4: case SERIALIZATION_TYPE_R4: + if (*pBlob + 4 <= endBlob) { + retValue = (ARG_SLOT)GET_UNALIGNED_VAL32(*pBlob); + *pBlob += 4; + break; + } + goto badBlob; + case SERIALIZATION_TYPE_I8: case SERIALIZATION_TYPE_U8: case SERIALIZATION_TYPE_R8: - case SERIALIZATION_TYPE_STRING: - pMTType = CoreLibBinder::GetElementType((CorElementType)objType); - RtnTypeHnd = TypeHandle(pMTType); - break; + if (*pBlob + 8 <= endBlob) { + retValue = (ARG_SLOT)GET_UNALIGNED_VAL64(*pBlob); + *pBlob += 8; + break; + } + goto badBlob; - case ELEMENT_TYPE_CLASS: - pMTType = CoreLibBinder::GetClass(CLASS__TYPE); - RtnTypeHnd = TypeHandle(pMTType); - break; + case SERIALIZATION_TYPE_STRING: + stringType: + { + int size = GetStringSize(pBlob, endBlob); + *bObjectCreated = TRUE; + if (size > 0) { + if (size > endBlob - *pBlob) // integer overflow check + goto badBlob; + retValue = ObjToArgSlot(StringObject::NewString((LPCUTF8)*pBlob, size)); + *pBlob += size; + } + else if (size == 0) + retValue = ObjToArgSlot(StringObject::NewString(0)); + else + *bObjectCreated = FALSE; - case SERIALIZATION_TYPE_TAGGED_OBJECT: - pMTType = g_pObjectClass; - RtnTypeHnd = TypeHandle(pMTType); break; + } - case SERIALIZATION_TYPE_TYPE: + // this is coming back from sig but it's not a serialization type, + // essentialy the type in the blob and the type in the sig don't match + case ELEMENT_TYPE_VALUETYPE: { - int size = GetStringSize(pBlob, endBlob); - if (size == -1) - return nullTH; + if (!th.IsEnum()) + goto badBlob; + CorSerializationType enumType = (CorSerializationType)th.GetInternalCorElementType(); + BOOL cannotBeObject = FALSE; + retValue = GetDataFromBlob(pCtorAssembly, enumType, nullTH, pBlob, endBlob, pModule, &cannotBeObject); + _ASSERTE(!cannotBeObject); + break; + } - if ((size+1 <= 1) || (size > endBlob - *pBlob)) - COMPlusThrow(kCustomAttributeFormatException); + // this is coming back from sig but it's not a serialization type, + // essentialy the type in the blob and the type in the sig don't match + case ELEMENT_TYPE_CLASS: + if (th.IsArray()) + goto typeArray; + else { + MethodTable *pMT = th.AsMethodTable(); + if (pMT == g_pStringClass) + goto stringType; + else if (pMT == g_pObjectClass) + goto typeObject; + else if (CoreLibBinder::IsClass(pMT, CLASS__TYPE)) + goto typeType; + } - LPUTF8 szName = (LPUTF8)_alloca(size + 1); - memcpy(szName, *pBlob, size); - *pBlob += size; - szName[size] = 0; + goto badBlob; - RtnTypeHnd = TypeName::GetTypeReferencedByCustomAttribute(szName, pModule->GetAssembly()); + case SERIALIZATION_TYPE_TYPE: + typeType: + { + typeHnd = GetTypeHandleFromBlob(pCtorAssembly, SERIALIZATION_TYPE_TYPE, pBlob, endBlob, pModule); + if (!typeHnd.IsNull()) + retValue = ObjToArgSlot(typeHnd.GetManagedClassObject()); + *bObjectCreated = TRUE; break; } - case SERIALIZATION_TYPE_ENUM: + // this is coming back from sig but it's not a serialization type, + // essentialy the type in the blob and the type in the sig don't match + case ELEMENT_TYPE_OBJECT: + case SERIALIZATION_TYPE_TAGGED_OBJECT: + typeObject: { - // get the enum type - BOOL isObject = FALSE; - ReflectClassBaseObject *pType = (ReflectClassBaseObject*)OBJECTREFToObject(ArgSlotToObj(GetDataFromBlob(pCtorAssembly, - SERIALIZATION_TYPE_TYPE, - nullTH, - pBlob, - endBlob, - pModule, - &isObject))); - if (pType != NULL) + // get the byte representing the real type and call GetDataFromBlob again + if (*pBlob + 1 > endBlob) + goto badBlob; + CorSerializationType objType = (CorSerializationType)**pBlob; + *pBlob += 1; + switch (objType) { + case SERIALIZATION_TYPE_SZARRAY: { - _ASSERTE(isObject); - RtnTypeHnd = pType->GetType(); - _ASSERTE((objType == SERIALIZATION_TYPE_ENUM) ? RtnTypeHnd.GetMethodTable()->IsEnum() : TRUE); + if (*pBlob + 1 > endBlob) + goto badBlob; + CorSerializationType arrayType = (CorSerializationType)**pBlob; + *pBlob += 1; + if (arrayType == SERIALIZATION_TYPE_TYPE) + arrayType = (CorSerializationType)ELEMENT_TYPE_CLASS; + // grab the array type and make a type handle for it + nullTH = GetTypeHandleFromBlob(pCtorAssembly, arrayType, pBlob, endBlob, pModule); + FALLTHROUGH; } - else + case SERIALIZATION_TYPE_TYPE: + case SERIALIZATION_TYPE_STRING: + // notice that the nullTH is actually not null in the array case (see case above) + retValue = GetDataFromBlob(pCtorAssembly, objType, nullTH, pBlob, endBlob, pModule, bObjectCreated); + _ASSERTE(*bObjectCreated || retValue == 0); + break; + case SERIALIZATION_TYPE_ENUM: { - RtnTypeHnd = TypeHandle(); + // + // get the enum type + typeHnd = GetTypeHandleFromBlob(pCtorAssembly, SERIALIZATION_TYPE_ENUM, pBlob, endBlob, pModule); + _ASSERTE(typeHnd.IsTypeDesc() == false); + + // ok we have the class, now we go and read the data + MethodTable *pMT = typeHnd.AsMethodTable(); + PREFIX_ASSUME(pMT != NULL); + CorSerializationType objNormType = (CorSerializationType)pMT->GetInternalCorElementType(); + BOOL isObject = FALSE; + retValue = GetDataFromBlob(pCtorAssembly, objNormType, nullTH, pBlob, endBlob, pModule, &isObject); + _ASSERTE(!isObject); + retValue= ObjToArgSlot(pMT->Box((void*)&retValue)); + *bObjectCreated = TRUE; + break; + } + default: + { + // the common primitive type case. We need to box the primitive + typeHnd = GetTypeHandleFromBlob(pCtorAssembly, objType, pBlob, endBlob, pModule); + _ASSERTE(typeHnd.IsTypeDesc() == false); + retValue = GetDataFromBlob(pCtorAssembly, objType, nullTH, pBlob, endBlob, pModule, bObjectCreated); + _ASSERTE(!*bObjectCreated); + retValue= ObjToArgSlot(typeHnd.AsMethodTable()->Box((void*)&retValue)); + *bObjectCreated = TRUE; + break; + } + } + break; + } + + case SERIALIZATION_TYPE_SZARRAY: + typeArray: + { + // read size + BOOL isObject = FALSE; + int size = (int)GetDataFromBlob(pCtorAssembly, SERIALIZATION_TYPE_I4, nullTH, pBlob, endBlob, pModule, &isObject); + _ASSERTE(!isObject); + + if (size != -1) { + CorSerializationType arrayType; + if (th.IsEnum()) + arrayType = SERIALIZATION_TYPE_ENUM; + else + arrayType = (CorSerializationType)th.GetInternalCorElementType(); + + BASEARRAYREF array = NULL; + GCPROTECT_BEGIN(array); + ReadArray(pCtorAssembly, arrayType, size, th, pBlob, endBlob, pModule, &array); + retValue = ObjToArgSlot(array); + GCPROTECT_END(); } + *bObjectCreated = TRUE; break; } default: + badBlob: + // generate a reasonable text string ("invalid blob or constructor") COMPlusThrow(kCustomAttributeFormatException); } - return RtnTypeHnd; + return retValue; } -// retrieve the string size in a CA blob. Advance the blob pointer to point to -// the beginning of the string immediately following the size -/*static*/ -int COMCustomAttribute::GetStringSize(BYTE **pBlob, const BYTE *endBlob) +extern "C" void QCALLTYPE CustomAttribute_CreateCustomAttributeInstance( + QCall::ModuleHandle pModule, + QCall::ObjectHandleOnStack pCaType, + QCall::ObjectHandleOnStack pMethod, + BYTE** ppBlob, + BYTE* pEndBlob, + INT32* pcNamedArgs, + QCall::ObjectHandleOnStack result) { - CONTRACTL - { - THROWS; - } - CONTRACTL_END; + QCALL_CONTRACT; - if (*pBlob >= endBlob ) - { // No buffer at all, or buffer overrun - COMPlusThrow(kCustomAttributeFormatException); - } + BEGIN_QCALL; - if (**pBlob == 0xFF) - { // Special case null string. - ++(*pBlob); - return -1; - } + GCX_COOP(); - ULONG ulSize; - if (FAILED(CPackedLen::SafeGetData((BYTE const *)*pBlob, (BYTE const *)endBlob, (ULONG *)&ulSize, (BYTE const **)pBlob))) + struct { - COMPlusThrow(kCustomAttributeFormatException); - } + REFLECTCLASSBASEREF refCaType; + OBJECTREF ca; + REFLECTMETHODREF refCtor; + } gc; + gc.refCaType = NULL; + gc.ca = NULL; + gc.refCtor = NULL; + GCPROTECT_BEGIN(gc); + { + gc.refCaType = (REFLECTCLASSBASEREF)pCaType.Get(); + gc.refCtor = (REFLECTMETHODREF)pMethod.Get(); - return (int)ulSize; -} + MethodDesc* pCtorMD = gc.refCtor->GetMethod(); + TypeHandle th = gc.refCaType->GetType(); -// copy the values of an array of integers from a CA blob -// (i.e., always stored in little-endian, and needs not be aligned). -// Returns TRUE on success, FALSE if the blob was not big enough. -// Advances *pBlob by the amount copied. -/*static*/ -template < typename T > -BOOL COMCustomAttribute::CopyArrayVAL(BASEARRAYREF pArray, int nElements, BYTE **pBlob, const BYTE *endBlob) -{ - int sizeData; // = size * 2; with integer overflow check - if (!ClrSafeInt::multiply(nElements, sizeof(T), sizeData)) - return FALSE; - if (sizeData > endBlob - *pBlob) // integer overflow check - return FALSE; -#if BIGENDIAN - T *ptDest = reinterpret_cast(pArray->GetDataPtr()); - for (int iElement = 0; iElement < nElements; iElement++) - { - T tValue; - BYTE *pbSrc = *pBlob + iElement * sizeof(T); - BYTE *pbDest = reinterpret_cast(&tValue); - for (size_t iByte = 0; iByte < sizeof(T); iByte++) - { - pbDest[sizeof(T) - 1 - iByte] = pbSrc[iByte]; - } - ptDest[iElement] = tValue; - } -#else // BIGENDIAN - memcpyNoGCRefs(pArray->GetDataPtr(), *pBlob, sizeData); -#endif // BIGENDIAN - *pBlob += sizeData; - return TRUE; -} + MethodDescCallSite ctorCallSite(pCtorMD, th); + MetaSig* pSig = ctorCallSite.GetMetaSig(); + BYTE* pBlob = *ppBlob; -// read the whole array as a chunk -/*static*/ -void COMCustomAttribute::ReadArray(Assembly *pCtorAssembly, - CorSerializationType arrayType, - int size, - TypeHandle th, - BYTE **pBlob, - const BYTE *endBlob, - Module *pModule, - BASEARRAYREF *pArray) -{ - CONTRACTL - { - THROWS; - } - CONTRACTL_END; + // get the number of arguments and allocate an array for the args + ARG_SLOT *args = NULL; + UINT cArgs = pSig->NumFixedArgs() + 1; // make room for the this pointer + UINT i = 1; // used to flag that we actually get the right number of arg from the blob - ARG_SLOT element = 0; + args = (ARG_SLOT*)_alloca(cArgs * sizeof(ARG_SLOT)); + memset((void*)args, 0, cArgs * sizeof(ARG_SLOT)); - switch ((DWORD)arrayType) { - case SERIALIZATION_TYPE_BOOLEAN: - case SERIALIZATION_TYPE_I1: - case SERIALIZATION_TYPE_U1: - *pArray = (BASEARRAYREF)AllocatePrimitiveArray((CorElementType)arrayType, size); - if (!CopyArrayVAL(*pArray, size, pBlob, endBlob)) - goto badBlob; - break; + OBJECTREF *argToProtect = (OBJECTREF*)_alloca(cArgs * sizeof(OBJECTREF)); + memset((void*)argToProtect, 0, cArgs * sizeof(OBJECTREF)); - case SERIALIZATION_TYPE_CHAR: - case SERIALIZATION_TYPE_I2: - case SERIALIZATION_TYPE_U2: - { - *pArray = (BASEARRAYREF)AllocatePrimitiveArray((CorElementType)arrayType, size); - if (!CopyArrayVAL(*pArray, size, pBlob, endBlob)) - goto badBlob; - break; - } - case SERIALIZATION_TYPE_I4: - case SERIALIZATION_TYPE_U4: - case SERIALIZATION_TYPE_R4: - { - *pArray = (BASEARRAYREF)AllocatePrimitiveArray((CorElementType)arrayType, size); - if (!CopyArrayVAL(*pArray, size, pBlob, endBlob)) - goto badBlob; - break; - } - case SERIALIZATION_TYPE_I8: - case SERIALIZATION_TYPE_U8: - case SERIALIZATION_TYPE_R8: - { - *pArray = (BASEARRAYREF)AllocatePrimitiveArray((CorElementType)arrayType, size); - if (!CopyArrayVAL(*pArray, size, pBlob, endBlob)) - goto badBlob; - break; - } - case ELEMENT_TYPE_CLASS: - case SERIALIZATION_TYPE_TYPE: - case SERIALIZATION_TYPE_STRING: - case SERIALIZATION_TYPE_SZARRAY: - case SERIALIZATION_TYPE_TAGGED_OBJECT: - { - BOOL isObject; + // load the this pointer + argToProtect[0] = gc.refCaType->GetType().GetMethodTable()->Allocate(); // this is the value to return after the ctor invocation - // If we haven't figured out the type of the array, throw bad blob exception - if (th.IsNull()) - goto badBlob; + if (pBlob) + { + if (pBlob < pEndBlob) + { + if (pBlob + 2 > pEndBlob) + { + COMPlusThrow(kCustomAttributeFormatException); + } + INT16 prolog = GET_UNALIGNED_VAL16(pBlob); + if (prolog != 1) + COMPlusThrow(kCustomAttributeFormatException); + pBlob += 2; + } - *pArray = (BASEARRAYREF)AllocateObjectArray(size, th); - if (arrayType == SERIALIZATION_TYPE_SZARRAY) - // switch the th to be the proper one - th = th.GetArrayElementTypeHandle(); - for (int i = 0; i < size; i++) { - element = GetDataFromBlob(pCtorAssembly, arrayType, th, pBlob, endBlob, pModule, &isObject); - _ASSERTE(isObject || element == NULL); - ((PTRARRAYREF)(*pArray))->SetAt(i, ArgSlotToObj(element)); + if (cArgs > 1) + { + GCPROTECT_ARRAY_BEGIN(*argToProtect, cArgs); + { + // loop through the args + for (i = 1; i < cArgs; i++) { + CorElementType type = pSig->NextArg(); + if (type == ELEMENT_TYPE_END) + break; + BOOL bObjectCreated = FALSE; + TypeHandle th = pSig->GetLastTypeHandleThrowing(); + if (th.IsArray()) + // get the array element + th = th.GetArrayElementTypeHandle(); + ARG_SLOT data = GetDataFromBlob(pCtorMD->GetAssembly(), (CorSerializationType)type, th, &pBlob, pEndBlob, pModule, &bObjectCreated); + if (bObjectCreated) + argToProtect[i] = ArgSlotToObj(data); + else + args[i] = data; + } + } + GCPROTECT_END(); + + // We have borrowed the signature from MethodDescCallSite. We have to put it back into the initial position + // because of that's where MethodDescCallSite expects to find it below. + pSig->Reset(); + + for (i = 1; i < cArgs; i++) + { + if (argToProtect[i] != NULL) + { + _ASSERTE(args[i] == NULL); + args[i] = ObjToArgSlot(argToProtect[i]); + } + } + } } - break; - } + args[0] = ObjToArgSlot(argToProtect[0]); - case SERIALIZATION_TYPE_ENUM: - { - INT32 bounds = size; + if (i != cArgs) + COMPlusThrow(kCustomAttributeFormatException); - // If we haven't figured out the type of the array, throw bad blob exception - if (th.IsNull()) - goto badBlob; + // check if there are any named properties to invoke, + // if so set the by ref int passed in to point + // to the blob position where name properties start + *pcNamedArgs = 0; - unsigned elementSize = th.GetSize(); - TypeHandle arrayHandle = ClassLoader::LoadArrayTypeThrowing(th); - if (arrayHandle.IsNull()) - goto badBlob; - *pArray = (BASEARRAYREF)AllocateSzArray(arrayHandle, bounds); - BOOL fSuccess; - switch (elementSize) + if (pBlob && pBlob != pEndBlob) { - case 1: - fSuccess = CopyArrayVAL(*pArray, size, pBlob, endBlob); - break; - case 2: - fSuccess = CopyArrayVAL(*pArray, size, pBlob, endBlob); - break; - case 4: - fSuccess = CopyArrayVAL(*pArray, size, pBlob, endBlob); - break; - case 8: - fSuccess = CopyArrayVAL(*pArray, size, pBlob, endBlob); - break; - default: - fSuccess = FALSE; + if (pBlob + 2 > pEndBlob) + COMPlusThrow(kCustomAttributeFormatException); + + *pcNamedArgs = GET_UNALIGNED_VAL16(pBlob); + + pBlob += 2; } - if (!fSuccess) - goto badBlob; - break; - } - default: - badBlob: - COMPlusThrow(kCustomAttributeFormatException); - } + *ppBlob = pBlob; + + if (*pcNamedArgs == 0 && pBlob != pEndBlob) + COMPlusThrow(kCustomAttributeFormatException); + // make the invocation to the ctor + gc.ca = ArgSlotToObj(args[0]); + if (pCtorMD->GetMethodTable()->IsValueType()) + args[0] = PtrToArgSlot(OBJECTREFToObject(gc.ca)->UnBox()); + + ctorCallSite.CallWithValueTypes(args); + + result.Set(gc.ca); + } + GCPROTECT_END(); + END_QCALL; } -// get data out of the blob according to a CorElementType -/*static*/ -ARG_SLOT COMCustomAttribute::GetDataFromBlob(Assembly *pCtorAssembly, - CorSerializationType type, - TypeHandle th, - BYTE **pBlob, - const BYTE *endBlob, - Module *pModule, - BOOL *bObjectCreated) +extern "C" void QCALLTYPE CustomAttribute_CreatePropertyOrFieldData( + QCall::ModuleHandle pModule, + BYTE** ppBlobStart, + BYTE* pBlobEnd, + QCall::StringHandleOnStack pName, + bool* pbIsProperty, + QCall::ObjectHandleOnStack pType, + QCall::ObjectHandleOnStack pValue) { - CONTRACTL - { - THROWS; - } - CONTRACTL_END; + QCALL_CONTRACT; - ARG_SLOT retValue = 0; - *bObjectCreated = FALSE; - TypeHandle nullTH; - TypeHandle typeHnd; + BEGIN_QCALL; - switch ((DWORD)type) { + BYTE* pBlob = *ppBlobStart; - case SERIALIZATION_TYPE_BOOLEAN: - case SERIALIZATION_TYPE_I1: - case SERIALIZATION_TYPE_U1: - if (*pBlob + 1 <= endBlob) { - retValue = (ARG_SLOT)**pBlob; - *pBlob += 1; - break; - } - goto badBlob; + GCX_COOP(); - case SERIALIZATION_TYPE_CHAR: - case SERIALIZATION_TYPE_I2: - case SERIALIZATION_TYPE_U2: - if (*pBlob + 2 <= endBlob) { - retValue = (ARG_SLOT)GET_UNALIGNED_VAL16(*pBlob); - *pBlob += 2; - break; - } - goto badBlob; + struct + { + STRINGREF Name; + OBJECTREF Type; + OBJECTREF Value; + } gc; + gc.Name = NULL; + gc.Type = NULL; + gc.Value = NULL; + GCPROTECT_BEGIN(gc); - case SERIALIZATION_TYPE_I4: - case SERIALIZATION_TYPE_U4: - case SERIALIZATION_TYPE_R4: - if (*pBlob + 4 <= endBlob) { - retValue = (ARG_SLOT)GET_UNALIGNED_VAL32(*pBlob); - *pBlob += 4; - break; - } - goto badBlob; + Assembly *pCtorAssembly = NULL; - case SERIALIZATION_TYPE_I8: - case SERIALIZATION_TYPE_U8: - case SERIALIZATION_TYPE_R8: - if (*pBlob + 8 <= endBlob) { - retValue = (ARG_SLOT)GET_UNALIGNED_VAL64(*pBlob); - *pBlob += 8; - break; - } - goto badBlob; + MethodTable *pMTValue = NULL; + CorSerializationType arrayType = SERIALIZATION_TYPE_BOOLEAN; + BOOL bObjectCreated = FALSE; + TypeHandle nullTH; - case SERIALIZATION_TYPE_STRING: - stringType: - { - int size = GetStringSize(pBlob, endBlob); - *bObjectCreated = TRUE; - if (size > 0) { - if (size > endBlob - *pBlob) // integer overflow check - goto badBlob; - retValue = ObjToArgSlot(StringObject::NewString((LPCUTF8)*pBlob, size)); - *pBlob += size; - } - else if (size == 0) - retValue = ObjToArgSlot(StringObject::NewString(0)); - else - *bObjectCreated = FALSE; + if (pBlob + 2 > pBlobEnd) + COMPlusThrow(kCustomAttributeFormatException); - break; - } + // get whether it is a field or a property + CorSerializationType propOrField = (CorSerializationType)*pBlob; + pBlob++; + if (propOrField == SERIALIZATION_TYPE_FIELD) + *pbIsProperty = FALSE; + else if (propOrField == SERIALIZATION_TYPE_PROPERTY) + *pbIsProperty = TRUE; + else + COMPlusThrow(kCustomAttributeFormatException); - // this is coming back from sig but it's not a serialization type, - // essentialy the type in the blob and the type in the sig don't match - case ELEMENT_TYPE_VALUETYPE: + // get the type of the field + CorSerializationType fieldType = (CorSerializationType)*pBlob; + pBlob++; + if (fieldType == SERIALIZATION_TYPE_SZARRAY) { - if (!th.IsEnum()) - goto badBlob; - CorSerializationType enumType = (CorSerializationType)th.GetInternalCorElementType(); - BOOL cannotBeObject = FALSE; - retValue = GetDataFromBlob(pCtorAssembly, enumType, nullTH, pBlob, endBlob, pModule, &cannotBeObject); - _ASSERTE(!cannotBeObject); - break; + arrayType = (CorSerializationType)*pBlob; + + if (pBlob + 1 > pBlobEnd) + COMPlusThrow(kCustomAttributeFormatException); + + pBlob++; } + if (fieldType == SERIALIZATION_TYPE_ENUM || arrayType == SERIALIZATION_TYPE_ENUM) + { + // get the enum type + ReflectClassBaseObject *pEnum = + (ReflectClassBaseObject*)OBJECTREFToObject(ArgSlotToObj(GetDataFromBlob( + pCtorAssembly, SERIALIZATION_TYPE_TYPE, nullTH, &pBlob, pBlobEnd, pModule, &bObjectCreated))); - // this is coming back from sig but it's not a serialization type, - // essentialy the type in the blob and the type in the sig don't match - case ELEMENT_TYPE_CLASS: - if (th.IsArray()) - goto typeArray; - else { - MethodTable *pMT = th.AsMethodTable(); - if (pMT == g_pStringClass) - goto stringType; - else if (pMT == g_pObjectClass) - goto typeObject; - else if (CoreLibBinder::IsClass(pMT, CLASS__TYPE)) - goto typeType; - } + if (pEnum == NULL) + COMPlusThrow(kCustomAttributeFormatException); - goto badBlob; + _ASSERTE(bObjectCreated); - case SERIALIZATION_TYPE_TYPE: - typeType: - { - typeHnd = GetTypeHandleFromBlob(pCtorAssembly, SERIALIZATION_TYPE_TYPE, pBlob, endBlob, pModule); - if (!typeHnd.IsNull()) - retValue = ObjToArgSlot(typeHnd.GetManagedClassObject()); - *bObjectCreated = TRUE; - break; + TypeHandle th = pEnum->GetType(); + _ASSERTE(th.IsEnum()); + + pMTValue = th.AsMethodTable(); + if (fieldType == SERIALIZATION_TYPE_ENUM) + // load the enum type to pass it back + gc.Type = th.GetManagedClassObject(); + else + nullTH = th; } - // this is coming back from sig but it's not a serialization type, - // essentialy the type in the blob and the type in the sig don't match - case ELEMENT_TYPE_OBJECT: - case SERIALIZATION_TYPE_TAGGED_OBJECT: - typeObject: + // get the string representing the field/property name + gc.Name = ArgSlotToString(GetDataFromBlob( + pCtorAssembly, SERIALIZATION_TYPE_STRING, nullTH, &pBlob, pBlobEnd, pModule, &bObjectCreated)); + _ASSERTE(bObjectCreated || gc.Name == NULL); + + // create the object and return it + switch (fieldType) { - // get the byte representing the real type and call GetDataFromBlob again - if (*pBlob + 1 > endBlob) - goto badBlob; - CorSerializationType objType = (CorSerializationType)**pBlob; - *pBlob += 1; - switch (objType) { - case SERIALIZATION_TYPE_SZARRAY: - { - if (*pBlob + 1 > endBlob) - goto badBlob; - CorSerializationType arrayType = (CorSerializationType)**pBlob; - *pBlob += 1; - if (arrayType == SERIALIZATION_TYPE_TYPE) - arrayType = (CorSerializationType)ELEMENT_TYPE_CLASS; - // grab the array type and make a type handle for it - nullTH = GetTypeHandleFromBlob(pCtorAssembly, arrayType, pBlob, endBlob, pModule); + case SERIALIZATION_TYPE_TAGGED_OBJECT: + gc.Type = g_pObjectClass->GetManagedClassObject(); FALLTHROUGH; - } case SERIALIZATION_TYPE_TYPE: case SERIALIZATION_TYPE_STRING: - // notice that the nullTH is actually not null in the array case (see case above) - retValue = GetDataFromBlob(pCtorAssembly, objType, nullTH, pBlob, endBlob, pModule, bObjectCreated); - _ASSERTE(*bObjectCreated || retValue == 0); + gc.Value = ArgSlotToObj(GetDataFromBlob( + pCtorAssembly, fieldType, nullTH, &pBlob, pBlobEnd, pModule, &bObjectCreated)); + _ASSERTE(bObjectCreated || gc.Value == NULL); + + if (gc.Value == NULL) + { + // load the proper type so that code in managed knows which property to load + if (fieldType == SERIALIZATION_TYPE_STRING) + gc.Type = CoreLibBinder::GetElementType(ELEMENT_TYPE_STRING)->GetManagedClassObject(); + else if (fieldType == SERIALIZATION_TYPE_TYPE) + gc.Type = CoreLibBinder::GetClass(CLASS__TYPE)->GetManagedClassObject(); + } break; - case SERIALIZATION_TYPE_ENUM: + case SERIALIZATION_TYPE_SZARRAY: { - // - // get the enum type - typeHnd = GetTypeHandleFromBlob(pCtorAssembly, SERIALIZATION_TYPE_ENUM, pBlob, endBlob, pModule); - _ASSERTE(typeHnd.IsTypeDesc() == false); + gc.Value = NULL; + int arraySize = (int)GetDataFromBlob(pCtorAssembly, SERIALIZATION_TYPE_I4, nullTH, &pBlob, pBlobEnd, pModule, &bObjectCreated); - // ok we have the class, now we go and read the data - MethodTable *pMT = typeHnd.AsMethodTable(); - PREFIX_ASSUME(pMT != NULL); - CorSerializationType objNormType = (CorSerializationType)pMT->GetInternalCorElementType(); - BOOL isObject = FALSE; - retValue = GetDataFromBlob(pCtorAssembly, objNormType, nullTH, pBlob, endBlob, pModule, &isObject); - _ASSERTE(!isObject); - retValue= ObjToArgSlot(pMT->Box((void*)&retValue)); - *bObjectCreated = TRUE; + if (arraySize != -1) + { + _ASSERTE(!bObjectCreated); + if (arrayType == SERIALIZATION_TYPE_STRING) + nullTH = TypeHandle(CoreLibBinder::GetElementType(ELEMENT_TYPE_STRING)); + else if (arrayType == SERIALIZATION_TYPE_TYPE) + nullTH = TypeHandle(CoreLibBinder::GetClass(CLASS__TYPE)); + else if (arrayType == SERIALIZATION_TYPE_TAGGED_OBJECT) + nullTH = TypeHandle(g_pObjectClass); + ReadArray(pCtorAssembly, arrayType, arraySize, nullTH, &pBlob, pBlobEnd, pModule, (BASEARRAYREF*)&gc.Value); + } + if (gc.Value == NULL) + { + TypeHandle arrayTH; + switch (arrayType) + { + case SERIALIZATION_TYPE_STRING: + arrayTH = TypeHandle(CoreLibBinder::GetElementType(ELEMENT_TYPE_STRING)); + break; + case SERIALIZATION_TYPE_TYPE: + arrayTH = TypeHandle(CoreLibBinder::GetClass(CLASS__TYPE)); + break; + case SERIALIZATION_TYPE_TAGGED_OBJECT: + arrayTH = TypeHandle(g_pObjectClass); + break; + default: + if (SERIALIZATION_TYPE_BOOLEAN <= arrayType && arrayType <= SERIALIZATION_TYPE_R8) + arrayTH = TypeHandle(CoreLibBinder::GetElementType((CorElementType)arrayType)); + } + if (!arrayTH.IsNull()) + { + arrayTH = ClassLoader::LoadArrayTypeThrowing(arrayTH); + gc.Type = arrayTH.GetManagedClassObject(); + } + } break; } default: - { - // the common primitive type case. We need to box the primitive - typeHnd = GetTypeHandleFromBlob(pCtorAssembly, objType, pBlob, endBlob, pModule); - _ASSERTE(typeHnd.IsTypeDesc() == false); - retValue = GetDataFromBlob(pCtorAssembly, objType, nullTH, pBlob, endBlob, pModule, bObjectCreated); - _ASSERTE(!*bObjectCreated); - retValue= ObjToArgSlot(typeHnd.AsMethodTable()->Box((void*)&retValue)); - *bObjectCreated = TRUE; - break; - } - } - break; - } - - case SERIALIZATION_TYPE_SZARRAY: - typeArray: - { - // read size - BOOL isObject = FALSE; - int size = (int)GetDataFromBlob(pCtorAssembly, SERIALIZATION_TYPE_I4, nullTH, pBlob, endBlob, pModule, &isObject); - _ASSERTE(!isObject); - - if (size != -1) { - CorSerializationType arrayType; - if (th.IsEnum()) - arrayType = SERIALIZATION_TYPE_ENUM; + if (SERIALIZATION_TYPE_BOOLEAN <= fieldType && fieldType <= SERIALIZATION_TYPE_R8) + pMTValue = CoreLibBinder::GetElementType((CorElementType)fieldType); + else if(fieldType == SERIALIZATION_TYPE_ENUM) + fieldType = (CorSerializationType)pMTValue->GetInternalCorElementType(); else - arrayType = (CorSerializationType)th.GetInternalCorElementType(); + COMPlusThrow(kCustomAttributeFormatException); - BASEARRAYREF array = NULL; - GCPROTECT_BEGIN(array); - ReadArray(pCtorAssembly, arrayType, size, th, pBlob, endBlob, pModule, &array); - retValue = ObjToArgSlot(array); - GCPROTECT_END(); - } - *bObjectCreated = TRUE; - break; - } + ARG_SLOT val = GetDataFromBlob(pCtorAssembly, fieldType, nullTH, &pBlob, pBlobEnd, pModule, &bObjectCreated); + _ASSERTE(!bObjectCreated); - default: - badBlob: - // generate a reasonable text string ("invalid blob or constructor") - COMPlusThrow(kCustomAttributeFormatException); + gc.Value = pMTValue->Box((void*)ArgSlotEndiannessFixup(&val, pMTValue->GetNumInstanceFieldBytes())); } - return retValue; + *ppBlobStart = pBlob; + pName.Set(gc.Name); + pType.Set(gc.Type); + pValue.Set(gc.Value); + + GCPROTECT_END(); + END_QCALL; } diff --git a/src/coreclr/vm/customattribute.h b/src/coreclr/vm/customattribute.h index 3c5fb7b6e5f62d..39b3fb63365fba 100644 --- a/src/coreclr/vm/customattribute.h +++ b/src/coreclr/vm/customattribute.h @@ -8,12 +8,11 @@ #include "fcall.h" #include "../md/compiler/custattr.h" -typedef Factory< SArray > CaValueArrayFactory; +using CaValueArrayFactory = Factory>; -class Attribute +namespace Attribute { -public: - static HRESULT ParseAttributeArgumentValues( + HRESULT ParseArgumentValues( void* pCa, INT32 cCa, CaValueArrayFactory* pCaValueArrayFactory, @@ -22,10 +21,10 @@ class Attribute CaNamedArg* pCaNamedArgs, COUNT_T cNamedArgs, DomainAssembly* pDomainAssembly); -}; +} extern "C" void QCALLTYPE CustomAttribute_CreateCustomAttributeInstance( - QCall::ObjectHandleOnStack pAttributedModule, + QCall::ModuleHandle pModule, QCall::ObjectHandleOnStack pCaType, QCall::ObjectHandleOnStack pMethod, BYTE** ppBlob, @@ -34,12 +33,12 @@ extern "C" void QCALLTYPE CustomAttribute_CreateCustomAttributeInstance( QCall::ObjectHandleOnStack result); extern "C" void QCALLTYPE CustomAttribute_CreatePropertyOrFieldData( - QCall::ObjectHandleOnStack pModule, + QCall::ModuleHandle pModule, BYTE** ppBlobStart, BYTE* pBlobEnd, - QCall::ObjectHandleOnStack pName, + QCall::StringHandleOnStack pName, bool* pbIsProperty, QCall::ObjectHandleOnStack pType, QCall::ObjectHandleOnStack value); -#endif +#endif // _CUSTOMATTRIBUTE_H_ From dc559992fd0c46fcea31beff560a4ac13f6f2c80 Mon Sep 17 00:00:00 2001 From: Aaron R Robinson Date: Fri, 22 Mar 2024 10:40:52 -0700 Subject: [PATCH 4/7] Feedback --- .../Reflection/RuntimeCustomAttributeData.cs | 17 +-- src/coreclr/vm/customattribute.cpp | 139 ++++++++++-------- src/coreclr/vm/customattribute.h | 2 +- 3 files changed, 84 insertions(+), 74 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttributeData.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttributeData.cs index 618e9b7f6b4668..48a1d5b5457758 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttributeData.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttributeData.cs @@ -9,7 +9,6 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; -using Internal; namespace System.Reflection { @@ -1837,16 +1836,16 @@ internal static AttributeUsageAttribute GetAttributeUsage(RuntimeType decoratedA (RuntimeModule)typeof(AttributeUsageAttribute).Module); // Convert parsed attribute arguments - AttributeTargets attrTargets = ctorParams[0].EncodedArgument is not null - ? (AttributeTargets)ctorParams[0].EncodedArgument!.PrimitiveValue.Byte4 - : 0; + AttributeTargets attrTargets = (AttributeTargets)(ctorParams[0].EncodedArgument?.PrimitiveValue.Byte4 ?? 0); - bool inherited = namedParams[0].EncodedArgument is not null - ? namedParams[0].EncodedArgument!.PrimitiveValue.Byte4 != 0 + CustomAttributeEncodedArgument? encodedArg = namedParams[0].EncodedArgument; + bool inherited = encodedArg is not null + ? encodedArg.PrimitiveValue.Byte4 != 0 : true; // default - bool allowMultiple = namedParams[1].EncodedArgument is not null - ? namedParams[1].EncodedArgument!.PrimitiveValue.Byte4 != 0 + encodedArg = namedParams[1].EncodedArgument; + bool allowMultiple = encodedArg is not null + ? encodedArg.PrimitiveValue.Byte4 != 0 : false; // default attributeUsageAttribute = new AttributeUsageAttribute(attrTargets, allowMultiple: allowMultiple, inherited: inherited); @@ -1927,7 +1926,7 @@ private static partial void CreatePropertyOrFieldData( ref IntPtr ppBlobStart, IntPtr pBlobEnd, StringHandleOnStack name, - [MarshalAs(UnmanagedType.U1)] out bool bIsProperty, + [MarshalAs(UnmanagedType.Bool)] out bool bIsProperty, ObjectHandleOnStack type, ObjectHandleOnStack value); diff --git a/src/coreclr/vm/customattribute.cpp b/src/coreclr/vm/customattribute.cpp index e5839d1c2993f7..4be95e171b8a75 100644 --- a/src/coreclr/vm/customattribute.cpp +++ b/src/coreclr/vm/customattribute.cpp @@ -352,7 +352,12 @@ HRESULT Attribute::ParseArgumentValues( // the beginning of the string immediately following the size static int GetStringSize(BYTE **pBlob, const BYTE *endBlob) { - STANDARD_VM_CONTRACT; + CONTRACTL + { + MODE_COOPERATIVE; + THROWS; + } + CONTRACTL_END; if (*pBlob >= endBlob ) { // No buffer at all, or buffer overrun @@ -389,7 +394,12 @@ static TypeHandle GetTypeHandleFromBlob(Assembly *pCtorAssembly, const BYTE *endBlob, Module *pModule) { - STANDARD_VM_CONTRACT; + CONTRACTL + { + MODE_COOPERATIVE; + THROWS; + } + CONTRACTL_END; // we must box which means we must get the method table, switch again on the element type MethodTable *pMTType = NULL; @@ -478,13 +488,20 @@ static TypeHandle GetTypeHandleFromBlob(Assembly *pCtorAssembly, // Returns TRUE on success, FALSE if the blob was not big enough. // Advances *pBlob by the amount copied. template -static BOOL CopyArrayVAL(BASEARRAYREF pArray, int nElements, BYTE **pBlob, const BYTE *endBlob) +static bool CopyArrayVAL(BASEARRAYREF pArray, int nElements, BYTE **pBlob, const BYTE *endBlob) { + CONTRACTL + { + MODE_COOPERATIVE; + NOTHROW; + } + CONTRACTL_END; + int sizeData; // = size * 2; with integer overflow check if (!ClrSafeInt::multiply(nElements, sizeof(T), sizeData)) - return FALSE; + return false; if (sizeData > endBlob - *pBlob) // integer overflow check - return FALSE; + return false; #if BIGENDIAN T *ptDest = reinterpret_cast(pArray->GetDataPtr()); for (int iElement = 0; iElement < nElements; iElement++) @@ -502,29 +519,36 @@ static BOOL CopyArrayVAL(BASEARRAYREF pArray, int nElements, BYTE **pBlob, const memcpyNoGCRefs(pArray->GetDataPtr(), *pBlob, sizeData); #endif // BIGENDIAN *pBlob += sizeData; - return TRUE; + return true; } // read the whole array as a chunk -static void ReadArray(Assembly *pCtorAssembly, +static BASEARRAYREF ReadArray(Assembly *pCtorAssembly, CorSerializationType arrayType, int size, TypeHandle th, BYTE **pBlob, const BYTE *endBlob, - Module *pModule, - BASEARRAYREF *pArray) + Module *pModule) { - STANDARD_VM_CONTRACT; + CONTRACTL + { + MODE_COOPERATIVE; + THROWS; + } + CONTRACTL_END; ARG_SLOT element = 0; + BASEARRAYREF array = NULL; + GCPROTECT_BEGIN(array); + switch ((DWORD)arrayType) { case SERIALIZATION_TYPE_BOOLEAN: case SERIALIZATION_TYPE_I1: case SERIALIZATION_TYPE_U1: - *pArray = (BASEARRAYREF)AllocatePrimitiveArray((CorElementType)arrayType, size); - if (!CopyArrayVAL(*pArray, size, pBlob, endBlob)) + array = (BASEARRAYREF)AllocatePrimitiveArray((CorElementType)arrayType, size); + if (!CopyArrayVAL(array, size, pBlob, endBlob)) goto badBlob; break; @@ -532,8 +556,8 @@ static void ReadArray(Assembly *pCtorAssembly, case SERIALIZATION_TYPE_I2: case SERIALIZATION_TYPE_U2: { - *pArray = (BASEARRAYREF)AllocatePrimitiveArray((CorElementType)arrayType, size); - if (!CopyArrayVAL(*pArray, size, pBlob, endBlob)) + array = (BASEARRAYREF)AllocatePrimitiveArray((CorElementType)arrayType, size); + if (!CopyArrayVAL(array, size, pBlob, endBlob)) goto badBlob; break; } @@ -541,8 +565,8 @@ static void ReadArray(Assembly *pCtorAssembly, case SERIALIZATION_TYPE_U4: case SERIALIZATION_TYPE_R4: { - *pArray = (BASEARRAYREF)AllocatePrimitiveArray((CorElementType)arrayType, size); - if (!CopyArrayVAL(*pArray, size, pBlob, endBlob)) + array = (BASEARRAYREF)AllocatePrimitiveArray((CorElementType)arrayType, size); + if (!CopyArrayVAL(array, size, pBlob, endBlob)) goto badBlob; break; } @@ -550,8 +574,8 @@ static void ReadArray(Assembly *pCtorAssembly, case SERIALIZATION_TYPE_U8: case SERIALIZATION_TYPE_R8: { - *pArray = (BASEARRAYREF)AllocatePrimitiveArray((CorElementType)arrayType, size); - if (!CopyArrayVAL(*pArray, size, pBlob, endBlob)) + array = (BASEARRAYREF)AllocatePrimitiveArray((CorElementType)arrayType, size); + if (!CopyArrayVAL(array, size, pBlob, endBlob)) goto badBlob; break; } @@ -567,14 +591,14 @@ static void ReadArray(Assembly *pCtorAssembly, if (th.IsNull()) goto badBlob; - *pArray = (BASEARRAYREF)AllocateObjectArray(size, th); + array = (BASEARRAYREF)AllocateObjectArray(size, th); if (arrayType == SERIALIZATION_TYPE_SZARRAY) // switch the th to be the proper one th = th.GetArrayElementTypeHandle(); for (int i = 0; i < size; i++) { element = GetDataFromBlob(pCtorAssembly, arrayType, th, pBlob, endBlob, pModule, &isObject); _ASSERTE(isObject || element == NULL); - ((PTRARRAYREF)(*pArray))->SetAt(i, ArgSlotToObj(element)); + ((PTRARRAYREF)(array))->SetAt(i, ArgSlotToObj(element)); } break; } @@ -591,21 +615,21 @@ static void ReadArray(Assembly *pCtorAssembly, TypeHandle arrayHandle = ClassLoader::LoadArrayTypeThrowing(th); if (arrayHandle.IsNull()) goto badBlob; - *pArray = (BASEARRAYREF)AllocateSzArray(arrayHandle, bounds); + array = (BASEARRAYREF)AllocateSzArray(arrayHandle, bounds); BOOL fSuccess; switch (elementSize) { case 1: - fSuccess = CopyArrayVAL(*pArray, size, pBlob, endBlob); + fSuccess = CopyArrayVAL(array, size, pBlob, endBlob); break; case 2: - fSuccess = CopyArrayVAL(*pArray, size, pBlob, endBlob); + fSuccess = CopyArrayVAL(array, size, pBlob, endBlob); break; case 4: - fSuccess = CopyArrayVAL(*pArray, size, pBlob, endBlob); + fSuccess = CopyArrayVAL(array, size, pBlob, endBlob); break; case 8: - fSuccess = CopyArrayVAL(*pArray, size, pBlob, endBlob); + fSuccess = CopyArrayVAL(array, size, pBlob, endBlob); break; default: fSuccess = FALSE; @@ -620,6 +644,8 @@ static void ReadArray(Assembly *pCtorAssembly, COMPlusThrow(kCustomAttributeFormatException); } + GCPROTECT_END(); + return array; } // get data out of the blob according to a CorElementType @@ -631,7 +657,12 @@ static ARG_SLOT GetDataFromBlob(Assembly *pCtorAssembly, Module *pModule, BOOL *bObjectCreated) { - STANDARD_VM_CONTRACT; + CONTRACTL + { + MODE_COOPERATIVE; + THROWS; + } + CONTRACTL_END; ARG_SLOT retValue = 0; *bObjectCreated = FALSE; @@ -817,11 +848,7 @@ static ARG_SLOT GetDataFromBlob(Assembly *pCtorAssembly, else arrayType = (CorSerializationType)th.GetInternalCorElementType(); - BASEARRAYREF array = NULL; - GCPROTECT_BEGIN(array); - ReadArray(pCtorAssembly, arrayType, size, th, pBlob, endBlob, pModule, &array); - retValue = ObjToArgSlot(array); - GCPROTECT_END(); + retValue = ObjToArgSlot(ReadArray(pCtorAssembly, arrayType, size, th, pBlob, endBlob, pModule)); } *bObjectCreated = TRUE; break; @@ -980,7 +1007,7 @@ extern "C" void QCALLTYPE CustomAttribute_CreatePropertyOrFieldData( BYTE** ppBlobStart, BYTE* pBlobEnd, QCall::StringHandleOnStack pName, - bool* pbIsProperty, + BOOL* pbIsProperty, QCall::ObjectHandleOnStack pType, QCall::ObjectHandleOnStack pValue) { @@ -992,17 +1019,6 @@ extern "C" void QCALLTYPE CustomAttribute_CreatePropertyOrFieldData( GCX_COOP(); - struct - { - STRINGREF Name; - OBJECTREF Type; - OBJECTREF Value; - } gc; - gc.Name = NULL; - gc.Type = NULL; - gc.Value = NULL; - GCPROTECT_BEGIN(gc); - Assembly *pCtorAssembly = NULL; MethodTable *pMTValue = NULL; @@ -1053,40 +1069,40 @@ extern "C" void QCALLTYPE CustomAttribute_CreatePropertyOrFieldData( pMTValue = th.AsMethodTable(); if (fieldType == SERIALIZATION_TYPE_ENUM) // load the enum type to pass it back - gc.Type = th.GetManagedClassObject(); + pType.Set(th.GetManagedClassObject()); else nullTH = th; } // get the string representing the field/property name - gc.Name = ArgSlotToString(GetDataFromBlob( - pCtorAssembly, SERIALIZATION_TYPE_STRING, nullTH, &pBlob, pBlobEnd, pModule, &bObjectCreated)); - _ASSERTE(bObjectCreated || gc.Name == NULL); + pName.Set(ArgSlotToString(GetDataFromBlob( + pCtorAssembly, SERIALIZATION_TYPE_STRING, nullTH, &pBlob, pBlobEnd, pModule, &bObjectCreated))); + _ASSERTE(bObjectCreated || pName.Get() == NULL); // create the object and return it switch (fieldType) { case SERIALIZATION_TYPE_TAGGED_OBJECT: - gc.Type = g_pObjectClass->GetManagedClassObject(); + pType.Set(g_pObjectClass->GetManagedClassObject()); FALLTHROUGH; case SERIALIZATION_TYPE_TYPE: case SERIALIZATION_TYPE_STRING: - gc.Value = ArgSlotToObj(GetDataFromBlob( - pCtorAssembly, fieldType, nullTH, &pBlob, pBlobEnd, pModule, &bObjectCreated)); - _ASSERTE(bObjectCreated || gc.Value == NULL); + pValue.Set(ArgSlotToObj(GetDataFromBlob( + pCtorAssembly, fieldType, nullTH, &pBlob, pBlobEnd, pModule, &bObjectCreated))); + _ASSERTE(bObjectCreated || pValue.Get() == NULL); - if (gc.Value == NULL) + if (pValue.Get() == NULL) { // load the proper type so that code in managed knows which property to load if (fieldType == SERIALIZATION_TYPE_STRING) - gc.Type = CoreLibBinder::GetElementType(ELEMENT_TYPE_STRING)->GetManagedClassObject(); + pType.Set(CoreLibBinder::GetElementType(ELEMENT_TYPE_STRING)->GetManagedClassObject()); else if (fieldType == SERIALIZATION_TYPE_TYPE) - gc.Type = CoreLibBinder::GetClass(CLASS__TYPE)->GetManagedClassObject(); + pType.Set(CoreLibBinder::GetClass(CLASS__TYPE)->GetManagedClassObject()); } break; case SERIALIZATION_TYPE_SZARRAY: { - gc.Value = NULL; + pValue.Set(NULL); int arraySize = (int)GetDataFromBlob(pCtorAssembly, SERIALIZATION_TYPE_I4, nullTH, &pBlob, pBlobEnd, pModule, &bObjectCreated); if (arraySize != -1) @@ -1098,9 +1114,9 @@ extern "C" void QCALLTYPE CustomAttribute_CreatePropertyOrFieldData( nullTH = TypeHandle(CoreLibBinder::GetClass(CLASS__TYPE)); else if (arrayType == SERIALIZATION_TYPE_TAGGED_OBJECT) nullTH = TypeHandle(g_pObjectClass); - ReadArray(pCtorAssembly, arrayType, arraySize, nullTH, &pBlob, pBlobEnd, pModule, (BASEARRAYREF*)&gc.Value); + pValue.Set(ReadArray(pCtorAssembly, arrayType, arraySize, nullTH, &pBlob, pBlobEnd, pModule)); } - if (gc.Value == NULL) + if (pValue.Get() == NULL) { TypeHandle arrayTH; switch (arrayType) @@ -1121,7 +1137,7 @@ extern "C" void QCALLTYPE CustomAttribute_CreatePropertyOrFieldData( if (!arrayTH.IsNull()) { arrayTH = ClassLoader::LoadArrayTypeThrowing(arrayTH); - gc.Type = arrayTH.GetManagedClassObject(); + pType.Set(arrayTH.GetManagedClassObject()); } } break; @@ -1137,14 +1153,9 @@ extern "C" void QCALLTYPE CustomAttribute_CreatePropertyOrFieldData( ARG_SLOT val = GetDataFromBlob(pCtorAssembly, fieldType, nullTH, &pBlob, pBlobEnd, pModule, &bObjectCreated); _ASSERTE(!bObjectCreated); - gc.Value = pMTValue->Box((void*)ArgSlotEndiannessFixup(&val, pMTValue->GetNumInstanceFieldBytes())); + pValue.Set(pMTValue->Box((void*)ArgSlotEndiannessFixup(&val, pMTValue->GetNumInstanceFieldBytes()))); } *ppBlobStart = pBlob; - pName.Set(gc.Name); - pType.Set(gc.Type); - pValue.Set(gc.Value); - - GCPROTECT_END(); END_QCALL; } diff --git a/src/coreclr/vm/customattribute.h b/src/coreclr/vm/customattribute.h index 39b3fb63365fba..b81c17ac55b974 100644 --- a/src/coreclr/vm/customattribute.h +++ b/src/coreclr/vm/customattribute.h @@ -37,7 +37,7 @@ extern "C" void QCALLTYPE CustomAttribute_CreatePropertyOrFieldData( BYTE** ppBlobStart, BYTE* pBlobEnd, QCall::StringHandleOnStack pName, - bool* pbIsProperty, + BOOL* pbIsProperty, QCall::ObjectHandleOnStack pType, QCall::ObjectHandleOnStack value); From b7b204ff4cb4fca269db26e03063621c5f3aa16a Mon Sep 17 00:00:00 2001 From: Aaron R Robinson Date: Fri, 22 Mar 2024 14:05:00 -0700 Subject: [PATCH 5/7] Bring back unmanaged parsing for AttributeUsage scenario --- .../Reflection/RuntimeCustomAttributeData.cs | 66 +++++++++---------- src/coreclr/vm/customattribute.cpp | 34 ++++++++++ src/coreclr/vm/customattribute.h | 7 ++ src/coreclr/vm/qcallentrypoints.cpp | 1 + 4 files changed, 74 insertions(+), 34 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttributeData.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttributeData.cs index 48a1d5b5457758..d1ffd93419d4dc 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttributeData.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttributeData.cs @@ -1801,23 +1801,6 @@ internal static AttributeUsageAttribute GetAttributeUsage(RuntimeType decoratedA AttributeUsageAttribute? attributeUsageAttribute = null; - CustomAttributeCtorParameter[] ctorParams = - { - new CustomAttributeCtorParameter(new CustomAttributeType((RuntimeType)typeof(int))) - }; - - CustomAttributeNamedParameter[] namedParams = - { - new CustomAttributeNamedParameter( - "Inherited", - CustomAttributeEncoding.Property, - new CustomAttributeType((RuntimeType)typeof(bool))), - new CustomAttributeNamedParameter( - "AllowMultiple", - CustomAttributeEncoding.Property, - new CustomAttributeType((RuntimeType)typeof(bool))), - }; - for (int i = 0; i < car.Length; i++) { ref CustomAttributeRecord caRecord = ref car[i]; @@ -1829,24 +1812,14 @@ internal static AttributeUsageAttribute GetAttributeUsage(RuntimeType decoratedA if (attributeUsageAttribute is not null) throw new FormatException(SR.Format(SR.Format_AttributeUsage, attributeType)); - CustomAttributeEncodedArgument.ParseAttributeArguments( + if (!ParseAttributeUsageAttribute( caRecord.blob, - ctorParams, - namedParams, - (RuntimeModule)typeof(AttributeUsageAttribute).Module); - - // Convert parsed attribute arguments - AttributeTargets attrTargets = (AttributeTargets)(ctorParams[0].EncodedArgument?.PrimitiveValue.Byte4 ?? 0); - - CustomAttributeEncodedArgument? encodedArg = namedParams[0].EncodedArgument; - bool inherited = encodedArg is not null - ? encodedArg.PrimitiveValue.Byte4 != 0 - : true; // default - - encodedArg = namedParams[1].EncodedArgument; - bool allowMultiple = encodedArg is not null - ? encodedArg.PrimitiveValue.Byte4 != 0 - : false; // default + out AttributeTargets attrTargets, + out bool allowMultiple, + out bool inherited)) + { + throw new CustomAttributeFormatException(); + } attributeUsageAttribute = new AttributeUsageAttribute(attrTargets, allowMultiple: allowMultiple, inherited: inherited); } @@ -1891,6 +1864,31 @@ internal static object[] CreateAttributeArrayHelper(RuntimeType caType, int elem } #endregion + [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "CustomAttribute_ParseAttributeUsageAttribute")] + [SuppressGCTransition] + private static partial int ParseAttributeUsageAttribute( + IntPtr pData, + int cData, + int* pTargets, + int* pAllowMultiple, + int* pInherited); + + private static bool ParseAttributeUsageAttribute( + ConstArray blob, + out AttributeTargets attrTargets, + out bool allowMultiple, + out bool inherited) + { + int attrTargetsLocal = 0; + int allowMultipleLocal = 0; + int inheritedLocal = 0; + int result = ParseAttributeUsageAttribute(blob.Signature, blob.Length, &attrTargetsLocal, &allowMultipleLocal, &inheritedLocal); + attrTargets = (AttributeTargets)attrTargetsLocal; + allowMultiple = allowMultipleLocal != 0; + inherited = inheritedLocal != 0; + return result != 0; + } + [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "CustomAttribute_CreateCustomAttributeInstance")] private static partial void CreateCustomAttributeInstance( QCallModule pModule, diff --git a/src/coreclr/vm/customattribute.cpp b/src/coreclr/vm/customattribute.cpp index 4be95e171b8a75..57ca258a25b18a 100644 --- a/src/coreclr/vm/customattribute.cpp +++ b/src/coreclr/vm/customattribute.cpp @@ -863,6 +863,40 @@ static ARG_SLOT GetDataFromBlob(Assembly *pCtorAssembly, return retValue; } +extern "C" BOOL QCALLTYPE CustomAttribute_ParseAttributeUsageAttribute( + PVOID pData, + ULONG cData, + ULONG* pTargets, + BOOL* pAllowMultiple, + BOOL* pInherited) +{ + QCALL_CONTRACT_NO_GC_TRANSITION; + + CustomAttributeParser ca(pData, cData); + CaArg args[1]; + args[0].InitEnum(SERIALIZATION_TYPE_I4, 0); + if (FAILED(::ParseKnownCaArgs(ca, args, ARRAY_SIZE(args)))) + return FALSE; + *pTargets = args[0].val.u4; + + // Define index values. + const int allowMultiple = 0; + const int inherited = 1; + + CaNamedArg namedArgs[2]; + CaType namedArgTypes[2]; + namedArgTypes[allowMultiple].Init(SERIALIZATION_TYPE_BOOLEAN); + namedArgTypes[inherited].Init(SERIALIZATION_TYPE_BOOLEAN); + namedArgs[allowMultiple].Init("AllowMultiple", SERIALIZATION_TYPE_PROPERTY, namedArgTypes[allowMultiple], FALSE); + namedArgs[inherited].Init("Inherited", SERIALIZATION_TYPE_PROPERTY, namedArgTypes[inherited], TRUE); + if (FAILED(::ParseKnownCaNamedArgs(ca, namedArgs, ARRAY_SIZE(namedArgs)))) + return FALSE; + + *pAllowMultiple = namedArgs[allowMultiple].val.boolean ? TRUE : FALSE; + *pInherited = namedArgs[inherited].val.boolean ? TRUE : FALSE; + return TRUE; +} + extern "C" void QCALLTYPE CustomAttribute_CreateCustomAttributeInstance( QCall::ModuleHandle pModule, QCall::ObjectHandleOnStack pCaType, diff --git a/src/coreclr/vm/customattribute.h b/src/coreclr/vm/customattribute.h index b81c17ac55b974..5ad802fc7fc0a3 100644 --- a/src/coreclr/vm/customattribute.h +++ b/src/coreclr/vm/customattribute.h @@ -23,6 +23,13 @@ namespace Attribute DomainAssembly* pDomainAssembly); } +extern "C" BOOL QCALLTYPE CustomAttribute_ParseAttributeUsageAttribute( + PVOID pData, + ULONG cData, + ULONG* pTargets, + BOOL* pAllowMultiple, + BOOL* pInherited); + extern "C" void QCALLTYPE CustomAttribute_CreateCustomAttributeInstance( QCall::ModuleHandle pModule, QCall::ObjectHandleOnStack pCaType, diff --git a/src/coreclr/vm/qcallentrypoints.cpp b/src/coreclr/vm/qcallentrypoints.cpp index ca8dda9fef878e..1150c55aa36d1a 100644 --- a/src/coreclr/vm/qcallentrypoints.cpp +++ b/src/coreclr/vm/qcallentrypoints.cpp @@ -81,6 +81,7 @@ static const Entry s_QCall[] = DllImportEntry(ArgIterator_GetNextArgType) DllImportEntry(ArgIterator_GetNextArg) DllImportEntry(ArgIterator_GetNextArg2) + DllImportEntry(CustomAttribute_ParseAttributeUsageAttribute) DllImportEntry(CustomAttribute_CreateCustomAttributeInstance) DllImportEntry(CustomAttribute_CreatePropertyOrFieldData) DllImportEntry(Enum_GetValuesAndNames) From 51bda16cae99b7be4e6039631f68142bb53aa25d Mon Sep 17 00:00:00 2001 From: Aaron R Robinson Date: Fri, 22 Mar 2024 15:51:18 -0700 Subject: [PATCH 6/7] Revert managed type changes. --- .../Reflection/RuntimeCustomAttributeData.cs | 27 ++++--------------- 1 file changed, 5 insertions(+), 22 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttributeData.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttributeData.cs index d1ffd93419d4dc..dd0b5cf897f4d0 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttributeData.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttributeData.cs @@ -766,7 +766,7 @@ private static void ParseNamedArgs( } // Match name - if (!namedParam.Name.Equals(argName)) + if (!namedParam.MemberInfo.Name.Equals(argName)) { continue; } @@ -1058,29 +1058,12 @@ internal sealed class CustomAttributeCtorParameter(CustomAttributeType type) public CustomAttributeEncodedArgument? EncodedArgument { get; set; } } - internal sealed class CustomAttributeNamedParameter + internal sealed class CustomAttributeNamedParameter(MemberInfo memberInfo, CustomAttributeEncoding fieldOrProperty, CustomAttributeType type) { - public CustomAttributeNamedParameter(MemberInfo memberInfo, CustomAttributeEncoding fieldOrProperty, CustomAttributeType type) - { - MemberInfo = memberInfo; - Name = MemberInfo.Name; - FieldOrProperty = fieldOrProperty; - CustomAttributeType = type; - } - - public CustomAttributeNamedParameter(string memberName, CustomAttributeEncoding fieldOrProperty, CustomAttributeType type) - { - MemberInfo = null; - Name = memberName; - FieldOrProperty = fieldOrProperty; - CustomAttributeType = type; - } - - public string Name { get; } - public CustomAttributeType CustomAttributeType { get; } - public CustomAttributeEncoding FieldOrProperty { get; } + public MemberInfo MemberInfo => memberInfo; + public CustomAttributeType CustomAttributeType => type; + public CustomAttributeEncoding FieldOrProperty => fieldOrProperty; public CustomAttributeEncodedArgument? EncodedArgument { get; set; } - public MemberInfo? MemberInfo { get; } } internal sealed class CustomAttributeType From 0265153293fa503c8447c950220c778ca2981a57 Mon Sep 17 00:00:00 2001 From: Aaron R Robinson Date: Fri, 22 Mar 2024 20:56:29 -0700 Subject: [PATCH 7/7] Review feedback. --- src/coreclr/vm/customattribute.cpp | 169 +++++++++++++---------------- 1 file changed, 76 insertions(+), 93 deletions(-) diff --git a/src/coreclr/vm/customattribute.cpp b/src/coreclr/vm/customattribute.cpp index 57ca258a25b18a..efa355602c90b4 100644 --- a/src/coreclr/vm/customattribute.cpp +++ b/src/coreclr/vm/customattribute.cpp @@ -912,127 +912,110 @@ extern "C" void QCALLTYPE CustomAttribute_CreateCustomAttributeInstance( GCX_COOP(); - struct - { - REFLECTCLASSBASEREF refCaType; - OBJECTREF ca; - REFLECTMETHODREF refCtor; - } gc; - gc.refCaType = NULL; - gc.ca = NULL; - gc.refCtor = NULL; - GCPROTECT_BEGIN(gc); - { - gc.refCaType = (REFLECTCLASSBASEREF)pCaType.Get(); - gc.refCtor = (REFLECTMETHODREF)pMethod.Get(); + MethodDesc* pCtorMD = ((REFLECTMETHODREF)pMethod.Get())->GetMethod(); + TypeHandle th = ((REFLECTCLASSBASEREF)pCaType.Get())->GetType(); - MethodDesc* pCtorMD = gc.refCtor->GetMethod(); - TypeHandle th = gc.refCaType->GetType(); + MethodDescCallSite ctorCallSite(pCtorMD, th); + MetaSig* pSig = ctorCallSite.GetMetaSig(); + BYTE* pBlob = *ppBlob; - MethodDescCallSite ctorCallSite(pCtorMD, th); - MetaSig* pSig = ctorCallSite.GetMetaSig(); - BYTE* pBlob = *ppBlob; + // get the number of arguments and allocate an array for the args + ARG_SLOT *args = NULL; + UINT cArgs = pSig->NumFixedArgs() + 1; // make room for the this pointer + UINT i = 1; // used to flag that we actually get the right number of arg from the blob - // get the number of arguments and allocate an array for the args - ARG_SLOT *args = NULL; - UINT cArgs = pSig->NumFixedArgs() + 1; // make room for the this pointer - UINT i = 1; // used to flag that we actually get the right number of arg from the blob + args = (ARG_SLOT*)_alloca(cArgs * sizeof(ARG_SLOT)); + memset((void*)args, 0, cArgs * sizeof(ARG_SLOT)); - args = (ARG_SLOT*)_alloca(cArgs * sizeof(ARG_SLOT)); - memset((void*)args, 0, cArgs * sizeof(ARG_SLOT)); + OBJECTREF *argToProtect = (OBJECTREF*)_alloca(cArgs * sizeof(OBJECTREF)); + memset((void*)argToProtect, 0, cArgs * sizeof(OBJECTREF)); - OBJECTREF *argToProtect = (OBJECTREF*)_alloca(cArgs * sizeof(OBJECTREF)); - memset((void*)argToProtect, 0, cArgs * sizeof(OBJECTREF)); + // load the this pointer + argToProtect[0] = th.GetMethodTable()->Allocate(); // this is the value to return after the ctor invocation - // load the this pointer - argToProtect[0] = gc.refCaType->GetType().GetMethodTable()->Allocate(); // this is the value to return after the ctor invocation - - if (pBlob) + if (pBlob) + { + if (pBlob < pEndBlob) { - if (pBlob < pEndBlob) + if (pBlob + 2 > pEndBlob) { - if (pBlob + 2 > pEndBlob) - { - COMPlusThrow(kCustomAttributeFormatException); - } - INT16 prolog = GET_UNALIGNED_VAL16(pBlob); - if (prolog != 1) - COMPlusThrow(kCustomAttributeFormatException); - pBlob += 2; + COMPlusThrow(kCustomAttributeFormatException); } + INT16 prolog = GET_UNALIGNED_VAL16(pBlob); + if (prolog != 1) + COMPlusThrow(kCustomAttributeFormatException); + pBlob += 2; + } - if (cArgs > 1) + if (cArgs > 1) + { + GCPROTECT_ARRAY_BEGIN(*argToProtect, cArgs); { - GCPROTECT_ARRAY_BEGIN(*argToProtect, cArgs); - { - // loop through the args - for (i = 1; i < cArgs; i++) { - CorElementType type = pSig->NextArg(); - if (type == ELEMENT_TYPE_END) - break; - BOOL bObjectCreated = FALSE; - TypeHandle th = pSig->GetLastTypeHandleThrowing(); - if (th.IsArray()) - // get the array element - th = th.GetArrayElementTypeHandle(); - ARG_SLOT data = GetDataFromBlob(pCtorMD->GetAssembly(), (CorSerializationType)type, th, &pBlob, pEndBlob, pModule, &bObjectCreated); - if (bObjectCreated) - argToProtect[i] = ArgSlotToObj(data); - else - args[i] = data; - } + // loop through the args + for (i = 1; i < cArgs; i++) { + CorElementType type = pSig->NextArg(); + if (type == ELEMENT_TYPE_END) + break; + BOOL bObjectCreated = FALSE; + TypeHandle th = pSig->GetLastTypeHandleThrowing(); + if (th.IsArray()) + // get the array element + th = th.GetArrayElementTypeHandle(); + ARG_SLOT data = GetDataFromBlob(pCtorMD->GetAssembly(), (CorSerializationType)type, th, &pBlob, pEndBlob, pModule, &bObjectCreated); + if (bObjectCreated) + argToProtect[i] = ArgSlotToObj(data); + else + args[i] = data; } - GCPROTECT_END(); + } + GCPROTECT_END(); - // We have borrowed the signature from MethodDescCallSite. We have to put it back into the initial position - // because of that's where MethodDescCallSite expects to find it below. - pSig->Reset(); + // We have borrowed the signature from MethodDescCallSite. We have to put it back into the initial position + // because of that's where MethodDescCallSite expects to find it below. + pSig->Reset(); - for (i = 1; i < cArgs; i++) + for (i = 1; i < cArgs; i++) + { + if (argToProtect[i] != NULL) { - if (argToProtect[i] != NULL) - { - _ASSERTE(args[i] == NULL); - args[i] = ObjToArgSlot(argToProtect[i]); - } + _ASSERTE(args[i] == NULL); + args[i] = ObjToArgSlot(argToProtect[i]); } } } - args[0] = ObjToArgSlot(argToProtect[0]); + } + args[0] = ObjToArgSlot(argToProtect[0]); - if (i != cArgs) - COMPlusThrow(kCustomAttributeFormatException); + if (i != cArgs) + COMPlusThrow(kCustomAttributeFormatException); - // check if there are any named properties to invoke, - // if so set the by ref int passed in to point - // to the blob position where name properties start - *pcNamedArgs = 0; + // check if there are any named properties to invoke, + // if so set the by ref int passed in to point + // to the blob position where name properties start + *pcNamedArgs = 0; - if (pBlob && pBlob != pEndBlob) - { - if (pBlob + 2 > pEndBlob) - COMPlusThrow(kCustomAttributeFormatException); + if (pBlob && pBlob != pEndBlob) + { + if (pBlob + 2 > pEndBlob) + COMPlusThrow(kCustomAttributeFormatException); - *pcNamedArgs = GET_UNALIGNED_VAL16(pBlob); + *pcNamedArgs = GET_UNALIGNED_VAL16(pBlob); - pBlob += 2; - } + pBlob += 2; + } - *ppBlob = pBlob; + *ppBlob = pBlob; - if (*pcNamedArgs == 0 && pBlob != pEndBlob) - COMPlusThrow(kCustomAttributeFormatException); + if (*pcNamedArgs == 0 && pBlob != pEndBlob) + COMPlusThrow(kCustomAttributeFormatException); - // make the invocation to the ctor - gc.ca = ArgSlotToObj(args[0]); - if (pCtorMD->GetMethodTable()->IsValueType()) - args[0] = PtrToArgSlot(OBJECTREFToObject(gc.ca)->UnBox()); + // make the invocation to the ctor + result.Set(ArgSlotToObj(args[0])); + if (pCtorMD->GetMethodTable()->IsValueType()) + args[0] = PtrToArgSlot(OBJECTREFToObject(result.Get())->UnBox()); - ctorCallSite.CallWithValueTypes(args); + ctorCallSite.CallWithValueTypes(args); - result.Set(gc.ca); - } - GCPROTECT_END(); END_QCALL; }