diff --git a/src/coreclr/System.Private.CoreLib/src/System/GC.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/GC.CoreCLR.cs index d3c962ad5cbb63..590fd5b18cee09 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/GC.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/GC.CoreCLR.cs @@ -106,9 +106,6 @@ internal enum GC_ALLOC_FLAGS [MethodImpl(MethodImplOptions.InternalCall)] internal static extern Array AllocateNewArray(IntPtr typeHandle, int length, GC_ALLOC_FLAGS flags); - [MethodImpl(MethodImplOptions.InternalCall)] - private static extern int GetGenerationWR(IntPtr handle); - [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "GCInterface_GetTotalMemory")] private static partial long GetTotalMemory(); @@ -290,9 +287,16 @@ public static void KeepAlive(object? obj) // public static int GetGeneration(WeakReference wo) { - int result = GetGenerationWR(wo.WeakHandle); + // Note - This throws an NRE if given a null weak reference. + object? obj = GCHandle.InternalGet(wo.WeakHandle); KeepAlive(wo); - return result; + + if (obj is null) + { + throw new ArgumentNullException(nameof(wo)); + } + + return GetGeneration(obj); } // Returns the maximum GC generation. Currently assumes only 1 heap. 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 b2c1855ea44d8d..1b3032a24607c4 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttributeData.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttributeData.cs @@ -1,12 +1,14 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Buffers.Binary; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Text; namespace System.Reflection { @@ -108,8 +110,7 @@ private static ReadOnlyCollection GetCombinedList(IList GetCustomAttributes(RuntimeModule module, int tkTarget) { CustomAttributeRecord[] records = GetCustomAttributeRecords(module, tkTarget); @@ -253,7 +235,6 @@ internal static CustomAttributeTypedArgument Filter(IList a private ConstructorInfo m_ctor = null!; private readonly RuntimeModule m_scope = null!; - private readonly MemberInfo[] m_members = null!; private readonly CustomAttributeCtorParameter[] m_ctorParams = null!; private readonly CustomAttributeNamedParameter[] m_namedParams = null!; private IList m_typedCtorArgs = null!; @@ -274,7 +255,7 @@ private RuntimeCustomAttributeData(RuntimeModule scope, MetadataToken caCtorToke if (m_ctor!.DeclaringType!.IsGenericType) { MetadataImport metadataScope = scope.MetadataImport; - var attributeType = scope.ResolveType(metadataScope.GetParentToken(caCtorToken), null, null)!; + Type attributeType = scope.ResolveType(metadataScope.GetParentToken(caCtorToken), null, null)!; m_ctor = (RuntimeConstructorInfo)scope.ResolveMethod(caCtorToken, attributeType.GenericTypeArguments, null)!.MethodHandle.GetMethodInfo(); } @@ -283,7 +264,7 @@ private RuntimeCustomAttributeData(RuntimeModule scope, MetadataToken caCtorToke { m_ctorParams = new CustomAttributeCtorParameter[parameters.Length]; for (int i = 0; i < parameters.Length; i++) - m_ctorParams[i] = new CustomAttributeCtorParameter(InitCustomAttributeType((RuntimeType)parameters[i].ParameterType)); + m_ctorParams[i] = new CustomAttributeCtorParameter(new CustomAttributeType((RuntimeType)parameters[i].ParameterType)); } else { @@ -292,35 +273,44 @@ private RuntimeCustomAttributeData(RuntimeModule scope, MetadataToken caCtorToke FieldInfo[] fields = m_ctor.DeclaringType!.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); PropertyInfo[] properties = m_ctor.DeclaringType.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + + // Allocate collections for members and names params. m_namedParams = new CustomAttributeNamedParameter[properties.Length + fields.Length]; - for (int i = 0; i < fields.Length; i++) - m_namedParams[i] = new CustomAttributeNamedParameter( - fields[i].Name, CustomAttributeEncoding.Field, InitCustomAttributeType((RuntimeType)fields[i].FieldType)); - for (int i = 0; i < properties.Length; i++) - m_namedParams[i + fields.Length] = new CustomAttributeNamedParameter( - properties[i].Name, CustomAttributeEncoding.Property, InitCustomAttributeType((RuntimeType)properties[i].PropertyType)); - m_members = new MemberInfo[fields.Length + properties.Length]; - fields.CopyTo(m_members, 0); - properties.CopyTo(m_members, fields.Length); + int idx = 0; + foreach (FieldInfo fi in fields) + { + m_namedParams[idx++] = new CustomAttributeNamedParameter( + fi, + CustomAttributeEncoding.Field, + new CustomAttributeType((RuntimeType)fi.FieldType)); + } + + foreach (PropertyInfo pi in properties) + { + m_namedParams[idx++] = new CustomAttributeNamedParameter( + pi, + CustomAttributeEncoding.Property, + new CustomAttributeType((RuntimeType)pi.PropertyType)); + } - CustomAttributeEncodedArgument.ParseAttributeArguments(blob, ref m_ctorParams, ref m_namedParams, m_scope); + CustomAttributeEncodedArgument.ParseAttributeArguments(blob, m_ctorParams, m_namedParams, m_scope); } #endregion #region Pseudo Custom Attribute Constructor internal RuntimeCustomAttributeData(Attribute attribute) { - if (attribute is DllImportAttribute dllImportAttribute) - Init(dllImportAttribute); - else if (attribute is FieldOffsetAttribute fieldOffsetAttribute) - Init(fieldOffsetAttribute); - else if (attribute is MarshalAsAttribute marshalAsAttribute) - Init(marshalAsAttribute); - else if (attribute is TypeForwardedToAttribute typeForwardedToAttribute) - Init(typeForwardedToAttribute); - else - Init(attribute); + if (attribute is DllImportAttribute dllImportAttribute) + Init(dllImportAttribute); + else if (attribute is FieldOffsetAttribute fieldOffsetAttribute) + Init(fieldOffsetAttribute); + else if (attribute is MarshalAsAttribute marshalAsAttribute) + Init(marshalAsAttribute); + else if (attribute is TypeForwardedToAttribute typeForwardedToAttribute) + Init(typeForwardedToAttribute); + else + Init(attribute); } private void Init(DllImportAttribute dllImport) { @@ -436,7 +426,7 @@ public override IList ConstructorArguments for (int i = 0; i < typedCtorArgs.Length; i++) { - CustomAttributeEncodedArgument encodedArg = m_ctorParams[i].CustomAttributeEncodedArgument; + CustomAttributeEncodedArgument encodedArg = m_ctorParams[i].EncodedArgument!; typedCtorArgs[i] = new CustomAttributeTypedArgument(m_scope, encodedArg); } @@ -462,10 +452,13 @@ public override IList NamedArguments int cNamedArgs = 0; if (m_namedParams is not null) { - for (int i = 0; i < m_namedParams.Length; i++) + foreach (CustomAttributeNamedParameter p in m_namedParams) { - if (m_namedParams[i].EncodedArgument.CustomAttributeType.EncodedType != CustomAttributeEncoding.Undefined) + if (p.EncodedArgument is not null + && p.EncodedArgument.CustomAttributeType.EncodedType != CustomAttributeEncoding.Undefined) + { cNamedArgs++; + } } } @@ -473,11 +466,16 @@ public override IList NamedArguments { CustomAttributeNamedArgument[] namedArgs = new CustomAttributeNamedArgument[cNamedArgs]; - for (int i = 0, j = 0; i < m_namedParams!.Length; i++) + int j = 0; + foreach (CustomAttributeNamedParameter p in m_namedParams!) { - if (m_namedParams[i].EncodedArgument.CustomAttributeType.EncodedType != CustomAttributeEncoding.Undefined) + if (p.EncodedArgument is not null + && p.EncodedArgument.CustomAttributeType.EncodedType != CustomAttributeEncoding.Undefined) + { namedArgs[j++] = new CustomAttributeNamedArgument( - m_members[i], new CustomAttributeTypedArgument(m_scope, m_namedParams[i].EncodedArgument)); + p.MemberInfo, + new CustomAttributeTypedArgument(m_scope, p.EncodedArgument)); + } } m_namedArgs = Array.AsReadOnly(namedArgs); @@ -522,51 +520,24 @@ private static Type CustomAttributeEncodingToType(CustomAttributeEncoding encode }; } -#pragma warning disable CA1859 - private static object EncodedValueToRawValue(long val, CustomAttributeEncoding encodedType) -#pragma warning restore + private static object EncodedValueToRawValue(PrimitiveValue val, CustomAttributeEncoding encodedType) { - switch (encodedType) + return encodedType switch { - case CustomAttributeEncoding.Boolean: - return (byte)val != 0; - - case CustomAttributeEncoding.Char: - return (char)val; - - case CustomAttributeEncoding.Byte: - return (byte)val; - - case CustomAttributeEncoding.SByte: - return (sbyte)val; - - case CustomAttributeEncoding.Int16: - return (short)val; - - case CustomAttributeEncoding.UInt16: - return (ushort)val; - - case CustomAttributeEncoding.Int32: - return (int)val; - - case CustomAttributeEncoding.UInt32: - return (uint)val; - - case CustomAttributeEncoding.Int64: - return (long)val; - - case CustomAttributeEncoding.UInt64: - return (ulong)val; - - case CustomAttributeEncoding.Float: - unsafe { return *(float*)&val; } - - case CustomAttributeEncoding.Double: - unsafe { return *(double*)&val; } - - default: - throw new ArgumentException(SR.Format(SR.Arg_EnumIllegalVal, (int)val), nameof(val)); - } + CustomAttributeEncoding.Boolean => (byte)val.Byte4 != 0, + CustomAttributeEncoding.Char => (char)val.Byte4, + CustomAttributeEncoding.Byte => (byte)val.Byte4, + CustomAttributeEncoding.SByte => (sbyte)val.Byte4, + CustomAttributeEncoding.Int16 => (short)val.Byte4, + CustomAttributeEncoding.UInt16 => (ushort)val.Byte4, + CustomAttributeEncoding.Int32 => val.Byte4, + CustomAttributeEncoding.UInt32 => (uint)val.Byte4, + CustomAttributeEncoding.Int64 => val.Byte8, + CustomAttributeEncoding.UInt64 => (ulong)val.Byte8, + CustomAttributeEncoding.Float => BitConverter.Int32BitsToSingle(val.Byte4), + CustomAttributeEncoding.Double => BitConverter.Int64BitsToDouble(val.Byte8), + _ => throw new ArgumentException(SR.Format(SR.Arg_EnumIllegalVal, val.Byte8), nameof(val)) + }; } private static RuntimeType ResolveType(RuntimeModule scope, string typeName) { @@ -585,7 +556,7 @@ internal CustomAttributeTypedArgument(RuntimeModule scope, CustomAttributeEncode if (encodedType == CustomAttributeEncoding.Enum) { - _argumentType = ResolveType(scope, encodedArg.CustomAttributeType.EnumName!); + _argumentType = encodedArg.CustomAttributeType.EnumType!; _value = EncodedValueToRawValue(encodedArg.PrimitiveValue, encodedArg.CustomAttributeType.EncodedEnumType); } else if (encodedType == CustomAttributeEncoding.String) @@ -609,7 +580,7 @@ internal CustomAttributeTypedArgument(RuntimeModule scope, CustomAttributeEncode if (encodedType == CustomAttributeEncoding.Enum) { - elementType = ResolveType(scope, encodedArg.CustomAttributeType.EnumName!); + elementType = encodedArg.CustomAttributeType.EnumType!; } else { @@ -639,7 +610,6 @@ internal CustomAttributeTypedArgument(RuntimeModule scope, CustomAttributeEncode } } - [StructLayout(LayoutKind.Auto)] internal struct CustomAttributeRecord { internal ConstArray blob; @@ -652,6 +622,7 @@ public CustomAttributeRecord(int token, ConstArray blob) } } + // See CorSerializationType in corhdr.h internal enum CustomAttributeEncoding : int { Undefined = 0, @@ -676,25 +647,22 @@ internal enum CustomAttributeEncoding : int Enum = 0x55 } - [StructLayout(LayoutKind.Auto)] - internal readonly struct CustomAttributeEncodedArgument + [StructLayout(LayoutKind.Explicit)] + internal struct PrimitiveValue { - private readonly long m_primitiveValue; - private readonly CustomAttributeEncodedArgument[] m_arrayValue; - private readonly string m_stringValue; - private readonly CustomAttributeType m_type; + [FieldOffset(0)] + public int Byte4; - [MethodImpl(MethodImplOptions.InternalCall)] - private static extern void ParseAttributeArguments( - IntPtr pCa, - int cCa, - ref CustomAttributeCtorParameter[] CustomAttributeCtorParameters, - ref CustomAttributeNamedParameter[] CustomAttributeTypedArgument, - RuntimeAssembly assembly); - - internal static void ParseAttributeArguments(ConstArray attributeBlob, - ref CustomAttributeCtorParameter[] customAttributeCtorParameters, - ref CustomAttributeNamedParameter[] customAttributeNamedParameters, + [FieldOffset(0)] + public long Byte8; + } + + internal sealed class CustomAttributeEncodedArgument + { + internal static void ParseAttributeArguments( + ConstArray attributeBlob, + CustomAttributeCtorParameter[] customAttributeCtorParameters, + CustomAttributeNamedParameter[] customAttributeNamedParameters, RuntimeModule customAttributeModule) { ArgumentNullException.ThrowIfNull(customAttributeModule); @@ -704,83 +672,446 @@ internal static void ParseAttributeArguments(ConstArray attributeBlob, if (customAttributeCtorParameters.Length != 0 || customAttributeNamedParameters.Length != 0) { - ParseAttributeArguments( - attributeBlob.Signature, - (int)attributeBlob.Length, - ref customAttributeCtorParameters, - ref customAttributeNamedParameters, - (RuntimeAssembly)customAttributeModule.Assembly); + CustomAttributeDataParser parser = new CustomAttributeDataParser(attributeBlob); + try + { + if (!parser.ValidateProlog()) + { + throw new BadImageFormatException(SR.Arg_CustomAttributeFormatException); + } + + ParseCtorArgs(ref parser, customAttributeCtorParameters, customAttributeModule); + ParseNamedArgs(ref parser, customAttributeNamedParameters, customAttributeModule); + } + catch (Exception ex) when (ex is not OutOfMemoryException) + { + throw new CustomAttributeFormatException(ex.Message, ex); + } } } - public CustomAttributeType CustomAttributeType => m_type; - public long PrimitiveValue => m_primitiveValue; - public CustomAttributeEncodedArgument[] ArrayValue => m_arrayValue; - public string StringValue => m_stringValue; - } + internal CustomAttributeEncodedArgument(CustomAttributeType type) + { + CustomAttributeType = type; + } - [StructLayout(LayoutKind.Auto)] - internal readonly struct CustomAttributeNamedParameter - { - private readonly string m_argumentName; - private readonly CustomAttributeEncoding m_fieldOrProperty; - private readonly CustomAttributeEncoding m_padding; - private readonly CustomAttributeType m_type; - private readonly CustomAttributeEncodedArgument m_encodedArgument; + public CustomAttributeType CustomAttributeType { get; } + public PrimitiveValue PrimitiveValue { get; set; } + public CustomAttributeEncodedArgument[]? ArrayValue { get; set; } + public string? StringValue { get; set; } - public CustomAttributeNamedParameter(string argumentName, CustomAttributeEncoding fieldOrProperty, CustomAttributeType type) + private static void ParseCtorArgs( + ref CustomAttributeDataParser parser, + CustomAttributeCtorParameter[] customAttributeCtorParameters, + RuntimeModule module) { - ArgumentNullException.ThrowIfNull(argumentName); + foreach (CustomAttributeCtorParameter p in customAttributeCtorParameters) + { + p.EncodedArgument = ParseCustomAttributeValue( + ref parser, + p.CustomAttributeType, + module); + } + } + + private static void ParseNamedArgs( + ref CustomAttributeDataParser parser, + CustomAttributeNamedParameter[] customAttributeNamedParameters, + RuntimeModule module) + { + // Parse the named arguments in the custom attribute. + int argCount = parser.GetI2(); + + for (int i = 0; i < argCount; ++i) + { + // Determine if a field or property. + CustomAttributeEncoding namedArgFieldOrProperty = parser.GetTag(); + if (namedArgFieldOrProperty is not CustomAttributeEncoding.Field + && namedArgFieldOrProperty is not CustomAttributeEncoding.Property) + { + throw new BadImageFormatException(SR.Arg_CustomAttributeFormatException); + } + + // Parse the encoded type for the named argument. + CustomAttributeType argType = ParseCustomAttributeType(ref parser, module); + + string? argName = parser.GetString(); + + // Argument name must be non-null and non-empty. + if (string.IsNullOrEmpty(argName)) + { + throw new BadImageFormatException(SR.Arg_CustomAttributeFormatException); + } - m_argumentName = argumentName; - m_fieldOrProperty = fieldOrProperty; - m_padding = fieldOrProperty; - m_type = type; - m_encodedArgument = default; + // Update the appropriate named argument element. + CustomAttributeNamedParameter? parameterToUpdate = null; + foreach (CustomAttributeNamedParameter namedParam in customAttributeNamedParameters) + { + CustomAttributeType namedArgType = namedParam.CustomAttributeType; + if (namedArgType.EncodedType != CustomAttributeEncoding.Object) + { + if (namedArgType.EncodedType != argType.EncodedType) + { + continue; + } + + // Match array type + if (argType.EncodedType is CustomAttributeEncoding.Array + && namedArgType.EncodedArrayType is not CustomAttributeEncoding.Object + && argType.EncodedArrayType != namedArgType.EncodedArrayType) + { + continue; + } + } + + // Match name + if (!namedParam.MemberInfo.Name.Equals(argName)) + { + continue; + } + + // If enum, match enum name. + if (namedArgType.EncodedType is CustomAttributeEncoding.Enum + || (namedArgType.EncodedType is CustomAttributeEncoding.Array + && namedArgType.EncodedArrayType is CustomAttributeEncoding.Enum)) + { + if (!ReferenceEquals(argType.EnumType, namedArgType.EnumType)) + { + continue; + } + + Debug.Assert(namedArgType.EncodedEnumType == argType.EncodedEnumType); + } + + // Found a match + parameterToUpdate = namedParam; + break; + } + + if (parameterToUpdate is null) + { + throw new BadImageFormatException(SR.Arg_CustomAttributeUnknownNamedArgument); + } + + if (parameterToUpdate.EncodedArgument is not null) + { + throw new BadImageFormatException(SR.Arg_CustomAttributeDuplicateNamedArgument); + } + + parameterToUpdate.EncodedArgument = ParseCustomAttributeValue(ref parser, argType, module); + } } - public CustomAttributeEncodedArgument EncodedArgument => m_encodedArgument; - } + private static CustomAttributeEncodedArgument ParseCustomAttributeValue( + ref CustomAttributeDataParser parser, + CustomAttributeType type, + RuntimeModule module) + { + CustomAttributeType attributeType = type.EncodedType == CustomAttributeEncoding.Object + ? ParseCustomAttributeType(ref parser, module) + : type; - [StructLayout(LayoutKind.Auto)] - internal readonly struct CustomAttributeCtorParameter - { - private readonly CustomAttributeType m_type; - private readonly CustomAttributeEncodedArgument m_encodedArgument; + CustomAttributeEncodedArgument arg = new(attributeType); + + CustomAttributeEncoding underlyingType = attributeType.EncodedType == CustomAttributeEncoding.Enum + ? attributeType.EncodedEnumType + : attributeType.EncodedType; + + switch (underlyingType) + { + case CustomAttributeEncoding.Boolean: + case CustomAttributeEncoding.Byte: + case CustomAttributeEncoding.SByte: + arg.PrimitiveValue = new PrimitiveValue() { Byte4 = parser.GetU1() }; + break; + case CustomAttributeEncoding.Char: + case CustomAttributeEncoding.Int16: + case CustomAttributeEncoding.UInt16: + arg.PrimitiveValue = new PrimitiveValue() { Byte4 = parser.GetU2() }; + break; + case CustomAttributeEncoding.Int32: + case CustomAttributeEncoding.UInt32: + arg.PrimitiveValue = new PrimitiveValue() { Byte4 = parser.GetI4() }; + break; + case CustomAttributeEncoding.Int64: + case CustomAttributeEncoding.UInt64: + arg.PrimitiveValue = new PrimitiveValue() { Byte8 = parser.GetI8() }; + break; + case CustomAttributeEncoding.Float: + arg.PrimitiveValue = new PrimitiveValue() { Byte4 = BitConverter.SingleToInt32Bits(parser.GetR4()) }; + break; + case CustomAttributeEncoding.Double: + arg.PrimitiveValue = new PrimitiveValue() { Byte8 = BitConverter.DoubleToInt64Bits(parser.GetR8()) }; + break; + case CustomAttributeEncoding.String: + case CustomAttributeEncoding.Type: + arg.StringValue = parser.GetString(); + break; + case CustomAttributeEncoding.Array: + { + arg.ArrayValue = null; + int len = parser.GetI4(); + if (len != -1) // indicates array is null - ECMA-335 II.23.3. + { + attributeType = new CustomAttributeType( + attributeType.EncodedArrayType, + CustomAttributeEncoding.Undefined, // Array type + attributeType.EncodedEnumType, + attributeType.EnumType); + arg.ArrayValue = new CustomAttributeEncodedArgument[len]; + for (int i = 0; i < len; ++i) + { + arg.ArrayValue[i] = ParseCustomAttributeValue(ref parser, attributeType, module); + } + } + break; + } + default: + throw new BadImageFormatException(); + } + + return arg; + } - public CustomAttributeCtorParameter(CustomAttributeType type) + private static CustomAttributeType ParseCustomAttributeType(ref CustomAttributeDataParser parser, RuntimeModule module) { - m_type = type; - m_encodedArgument = default; + CustomAttributeEncoding arrayTag = CustomAttributeEncoding.Undefined; + CustomAttributeEncoding enumTag = CustomAttributeEncoding.Undefined; + Type? enumType = null; + + CustomAttributeEncoding tag = parser.GetTag(); + if (tag is CustomAttributeEncoding.Array) + { + arrayTag = parser.GetTag(); + } + + // Load the enum type if needed. + if (tag is CustomAttributeEncoding.Enum + || (tag is CustomAttributeEncoding.Array + && arrayTag is CustomAttributeEncoding.Enum)) + { + // We cannot determine the underlying type without loading the enum. + string? enumTypeMaybe = parser.GetString(); + if (enumTypeMaybe is null) + { + throw new BadImageFormatException(); + } + + enumType = TypeNameParser.GetTypeReferencedByCustomAttribute(enumTypeMaybe, module); + if (!enumType.IsEnum) + { + throw new BadImageFormatException(); + } + + enumTag = RuntimeCustomAttributeData.TypeToCustomAttributeEncoding((RuntimeType)enumType.GetEnumUnderlyingType()); + } + + return new CustomAttributeType(tag, arrayTag, enumTag, enumType); + } + + /// + /// Used to parse CustomAttribute data. See ECMA-335 II.23.3. + /// + private ref struct CustomAttributeDataParser + { + private int _curr; + private ReadOnlySpan _blob; + + public CustomAttributeDataParser(ConstArray attributeBlob) + { + unsafe + { + _blob = new ReadOnlySpan((void*)attributeBlob.Signature, attributeBlob.Length); + } + _curr = 0; + } + + private ReadOnlySpan PeekData(int size) => _blob.Slice(_curr, size); + + private ReadOnlySpan ReadData(int size) + { + ReadOnlySpan tmp = PeekData(size); + Debug.Assert(size <= (_blob.Length - _curr)); + _curr += size; + return tmp; + } + + public byte GetU1() + { + ReadOnlySpan tmp = ReadData(sizeof(byte)); + return tmp[0]; + } + + public sbyte GetI1() => (sbyte)GetU1(); + + public ushort GetU2() + { + ReadOnlySpan tmp = ReadData(sizeof(ushort)); + return BinaryPrimitives.ReadUInt16LittleEndian(tmp); + } + + public short GetI2() => (short)GetU2(); + + public uint GetU4() + { + ReadOnlySpan tmp = ReadData(sizeof(uint)); + return BinaryPrimitives.ReadUInt32LittleEndian(tmp); + } + + public int GetI4() => (int)GetU4(); + + public ulong GetU8() + { + ReadOnlySpan tmp = ReadData(sizeof(ulong)); + return BinaryPrimitives.ReadUInt64LittleEndian(tmp); + } + + public long GetI8() => (long)GetU8(); + + public float GetR4() + { + ReadOnlySpan tmp = ReadData(sizeof(float)); + return BinaryPrimitives.ReadSingleLittleEndian(tmp); + } + + public CustomAttributeEncoding GetTag() + { + return (CustomAttributeEncoding)GetI1(); + } + + public double GetR8() + { + ReadOnlySpan tmp = ReadData(sizeof(double)); + return BinaryPrimitives.ReadDoubleLittleEndian(tmp); + } + + public ushort GetProlog() => GetU2(); + + public bool ValidateProlog() + { + ushort val = GetProlog(); + return val == 0x0001; + } + + public string? GetString() + { + byte packedLengthBegin = PeekData(sizeof(byte))[0]; + + // Check if the embedded string indicates a 'null' string (0xff). + if (packedLengthBegin == 0xff) // ECMA 335- II.23.3 + { + // Consume the indicator. + ReadData(1); + return null; + } + + // Not a null string, return a non-null string value. + // The embedded string a UTF-8 prefixed by an ECMA-335 packed integer. + int length = GetPackedLength(packedLengthBegin); + if (length == 0) + { + return string.Empty; + } + + ReadOnlySpan utf8ByteSpan = ReadData(length); + return Encoding.UTF8.GetString(utf8ByteSpan); + } + + private int GetPackedLength(byte firstByte) + { + if ((firstByte & 0x80) == 0) + { + // Consume one byte. + ReadData(1); + return firstByte & 0x7f; + } + + int len; + ReadOnlySpan data; + if ((firstByte & 0xC0) == 0x80) + { + // Consume the bytes. + data = ReadData(2); + len = (data[0] & 0x3f) << 8; + return len + data[1]; + } + + if ((firstByte & 0xE0) == 0xC0) + { + // Consume the bytes. + data = ReadData(4); + len = (data[0] & 0x1f) << 24; + len += data[1] << 16; + len += data[2] << 8; + return len + data[3]; + } + + throw new OverflowException(); + } } + } - public CustomAttributeEncodedArgument CustomAttributeEncodedArgument => m_encodedArgument; + internal sealed class CustomAttributeCtorParameter(CustomAttributeType type) + { + public CustomAttributeType CustomAttributeType => type; + public CustomAttributeEncodedArgument? EncodedArgument { get; set; } } - [StructLayout(LayoutKind.Auto)] - internal readonly struct CustomAttributeType + internal sealed class CustomAttributeNamedParameter(MemberInfo memberInfo, CustomAttributeEncoding fieldOrProperty, CustomAttributeType type) { + public MemberInfo MemberInfo => memberInfo; + public CustomAttributeType CustomAttributeType => type; + public CustomAttributeEncoding FieldOrProperty => fieldOrProperty; + public CustomAttributeEncodedArgument? EncodedArgument { get; set; } + } + + internal sealed class CustomAttributeType + { + public CustomAttributeType( + CustomAttributeEncoding encodedType, + CustomAttributeEncoding encodedArrayType, + CustomAttributeEncoding encodedEnumType, + Type? enumType) + { + EncodedType = encodedType; + EncodedArrayType = encodedArrayType; + EncodedEnumType = encodedEnumType; + EnumType = enumType; + } + + public CustomAttributeType(RuntimeType parameterType) + { + Debug.Assert(parameterType is not null); + CustomAttributeEncoding encodedType = RuntimeCustomAttributeData.TypeToCustomAttributeEncoding(parameterType); + CustomAttributeEncoding encodedArrayType = CustomAttributeEncoding.Undefined; + CustomAttributeEncoding encodedEnumType = CustomAttributeEncoding.Undefined; + Type? enumType = null; + + if (encodedType == CustomAttributeEncoding.Array) + { + parameterType = (RuntimeType)parameterType.GetElementType(); + encodedArrayType = RuntimeCustomAttributeData.TypeToCustomAttributeEncoding(parameterType); + } + + if (encodedType == CustomAttributeEncoding.Enum + || encodedArrayType == CustomAttributeEncoding.Enum) + { + enumType = parameterType; + encodedEnumType = RuntimeCustomAttributeData.TypeToCustomAttributeEncoding((RuntimeType)Enum.GetUnderlyingType(parameterType)); + } + + EncodedType = encodedType; + EncodedArrayType = encodedArrayType; + EncodedEnumType = encodedEnumType; + EnumType = enumType; + } + + public CustomAttributeEncoding EncodedType { get; } + public CustomAttributeEncoding EncodedEnumType { get; } + public CustomAttributeEncoding EncodedArrayType { get; } + /// The most complicated type is an enum[] in which case... - private readonly string? m_enumName; // ...enum name - private readonly CustomAttributeEncoding m_encodedType; // ...array - private readonly CustomAttributeEncoding m_encodedEnumType; // ...enum - private readonly CustomAttributeEncoding m_encodedArrayType; // ...enum type - private readonly CustomAttributeEncoding m_padding; - - public CustomAttributeType(CustomAttributeEncoding encodedType, CustomAttributeEncoding encodedArrayType, - CustomAttributeEncoding encodedEnumType, string? enumName) - { - m_encodedType = encodedType; - m_encodedArrayType = encodedArrayType; - m_encodedEnumType = encodedEnumType; - m_enumName = enumName; - m_padding = m_encodedType; - } - - public CustomAttributeEncoding EncodedType => m_encodedType; - public CustomAttributeEncoding EncodedEnumType => m_encodedEnumType; - public CustomAttributeEncoding EncodedArrayType => m_encodedArrayType; - public string? EnumName => m_enumName; + public Type? EnumType { get; } } internal static unsafe class CustomAttribute diff --git a/src/coreclr/inc/contract.inl b/src/coreclr/inc/contract.inl index 06ee1ef06d0347..d614f84e74f2a9 100644 --- a/src/coreclr/inc/contract.inl +++ b/src/coreclr/inc/contract.inl @@ -493,7 +493,7 @@ void CONTRACT_ASSERT(const char *szElaboration, { char Buf[512*20 + 2048 + 1024]; - sprintf_s(Buf,ARRAY_SIZE(Buf), "CONTRACT VIOLATION by %s at \"%s\" @ %d\n\n%s\n", szFunction, szFile, lineNum, szElaboration); + sprintf_s(Buf,ARRAY_SIZE(Buf), "CONTRACT VIOLATION by %s at \"%s\":%d\n\n%s\n", szFunction, szFile, lineNum, szElaboration); int count = 20; ContractStackRecord *pRec = CheckClrDebugState() ? CheckClrDebugState()->GetContractStackTrace() : NULL; @@ -530,7 +530,7 @@ void CONTRACT_ASSERT(const char *szElaboration, } sprintf_s(tmpbuf,ARRAY_SIZE(tmpbuf), - "\n%s %s in %s at \"%s\" @ %d", + "\n%s %s in %s at \"%s\":%d", fshowconflict ? "VIOLATED-->" : " ", pRec->m_construct, pRec->m_szFunction, diff --git a/src/coreclr/utilcode/debug.cpp b/src/coreclr/utilcode/debug.cpp index dfc323744363c0..363ff6599bab3f 100644 --- a/src/coreclr/utilcode/debug.cpp +++ b/src/coreclr/utilcode/debug.cpp @@ -236,7 +236,7 @@ bool _DbgBreakCheck( sprintf_s(formatBuffer, sizeof(formatBuffer), "\nAssert failure(PID %d [0x%08x], Thread: %d [0x%04x]): %s\n" - " File: %s Line: %d\n" + " File: %s:%d\n" " Image: %s\n\n", GetCurrentProcessId(), GetCurrentProcessId(), GetCurrentThreadId(), GetCurrentThreadId(), @@ -517,7 +517,7 @@ void DECLSPEC_NORETURN __FreeBuildAssertFail(const char *szFile, int iLine, cons SString buffer; buffer.Printf("CLR: Assert failure(PID %d [0x%08x], Thread: %d [0x%x]): %s\n" - " File: %s, Line: %d Image:\n%s\n", + " File: %s:%d Image:\n%s\n", GetCurrentProcessId(), GetCurrentProcessId(), GetCurrentThreadId(), GetCurrentThreadId(), szExpr, szFile, iLine, modulePath.GetUTF8()); @@ -528,7 +528,7 @@ void DECLSPEC_NORETURN __FreeBuildAssertFail(const char *szFile, int iLine, cons // Log to the stress log. Note that we can't include the szExpr b/c that // may not be a string literal (particularly for formatt-able asserts). - STRESS_LOG2(LF_ASSERT, LL_ALWAYS, "ASSERT:%s, line:%d\n", szFile, iLine); + STRESS_LOG2(LF_ASSERT, LL_ALWAYS, "ASSERT:%s:%d\n", szFile, iLine); FailFastOnAssert(); UNREACHABLE(); diff --git a/src/coreclr/vm/comutilnative.cpp b/src/coreclr/vm/comutilnative.cpp index c016311cd62314..f486a777c7c705 100644 --- a/src/coreclr/vm/comutilnative.cpp +++ b/src/coreclr/vm/comutilnative.cpp @@ -795,33 +795,6 @@ extern "C" int QCALLTYPE GCInterface_EndNoGCRegion() return retVal; } -/*===============================GetGenerationWR================================ -**Action: Returns the generation in which the object pointed to by a WeakReference is found. -**Returns: -**Arguments: args->handle -- the OBJECTHANDLE to the object which we're locating. -**Exceptions: ArgumentException if handle points to an object which is not accessible. -==============================================================================*/ -FCIMPL1(int, GCInterface::GetGenerationWR, LPVOID handle) -{ - FCALL_CONTRACT; - - int iRetVal = 0; - - HELPER_METHOD_FRAME_BEGIN_RET_0(); - - OBJECTREF temp; - temp = ObjectFromHandle((OBJECTHANDLE) handle); - if (temp == NULL) - COMPlusThrowArgumentNull(W("wo")); - - iRetVal = (INT32)GCHeapUtilities::GetGCHeap()->WhichGeneration(OBJECTREFToObject(temp)); - - HELPER_METHOD_FRAME_END(); - - return iRetVal; -} -FCIMPLEND - FCIMPL0(int, GCInterface::GetLastGCPercentTimeInGC) { FCALL_CONTRACT; diff --git a/src/coreclr/vm/comutilnative.h b/src/coreclr/vm/comutilnative.h index 2152d1f89b85b5..22fa0201583a7a 100644 --- a/src/coreclr/vm/comutilnative.h +++ b/src/coreclr/vm/comutilnative.h @@ -160,7 +160,6 @@ class GCInterface { static FCDECL1(void, SetLOHCompactionMode, int newLOHCompactionyMode); static FCDECL2(FC_BOOL_RET, RegisterForFullGCNotification, UINT32 gen2Percentage, UINT32 lohPercentage); static FCDECL0(FC_BOOL_RET, CancelFullGCNotification); - static FCDECL1(int, GetGenerationWR, LPVOID handle); static FCDECL1(int, GetGeneration, Object* objUNSAFE); static FCDECL0(UINT64, GetSegmentSize); static FCDECL0(int, GetLastGCPercentTimeInGC); diff --git a/src/coreclr/vm/corelib.h b/src/coreclr/vm/corelib.h index 2fc34d04372c5e..9168ef4ed0884b 100644 --- a/src/coreclr/vm/corelib.h +++ b/src/coreclr/vm/corelib.h @@ -216,31 +216,6 @@ DEFINE_FIELD(STUBMETHODINFO, HANDLE, m_value) DEFINE_CLASS(CONSTRUCTOR_INFO, Reflection, ConstructorInfo) -DEFINE_CLASS_U(Reflection, CustomAttributeEncodedArgument, CustomAttributeValue) -DEFINE_FIELD_U(m_primitiveValue, CustomAttributeValue, m_rawValue) -DEFINE_FIELD_U(m_arrayValue, CustomAttributeValue, m_value) -DEFINE_FIELD_U(m_stringValue, CustomAttributeValue, m_enumOrTypeName) -DEFINE_FIELD_U(m_type, CustomAttributeValue, m_type) -DEFINE_CLASS(CUSTOM_ATTRIBUTE_ENCODED_ARGUMENT, Reflection, CustomAttributeEncodedArgument) - -DEFINE_CLASS_U(Reflection, CustomAttributeNamedParameter, CustomAttributeNamedArgument) -DEFINE_FIELD_U(m_argumentName, CustomAttributeNamedArgument, m_argumentName) -DEFINE_FIELD_U(m_fieldOrProperty, CustomAttributeNamedArgument, m_propertyOrField) -DEFINE_FIELD_U(m_padding, CustomAttributeNamedArgument, m_padding) -DEFINE_FIELD_U(m_type, CustomAttributeNamedArgument, m_type) -DEFINE_FIELD_U(m_encodedArgument, CustomAttributeNamedArgument, m_value) - -DEFINE_CLASS_U(Reflection, CustomAttributeCtorParameter, CustomAttributeArgument) -DEFINE_FIELD_U(m_type, CustomAttributeArgument, m_type) -DEFINE_FIELD_U(m_encodedArgument, CustomAttributeArgument, m_value) - -DEFINE_CLASS_U(Reflection, CustomAttributeType, CustomAttributeType) -DEFINE_FIELD_U(m_enumName, CustomAttributeType, m_enumName) -DEFINE_FIELD_U(m_encodedType, CustomAttributeType, m_tag) -DEFINE_FIELD_U(m_encodedEnumType, CustomAttributeType, m_enumType) -DEFINE_FIELD_U(m_encodedArrayType, CustomAttributeType, m_arrayType) -DEFINE_FIELD_U(m_padding, CustomAttributeType, m_padding) - DEFINE_CLASS_U(Globalization, CultureInfo, CultureInfoBaseObject) DEFINE_FIELD_U(_compareInfo, CultureInfoBaseObject, _compareInfo) DEFINE_FIELD_U(_textInfo, CultureInfoBaseObject, _textInfo) diff --git a/src/coreclr/vm/customattribute.cpp b/src/coreclr/vm/customattribute.cpp index 71ee134e8a8c54..b86ca79db92819 100644 --- a/src/coreclr/vm/customattribute.cpp +++ b/src/coreclr/vm/customattribute.cpp @@ -10,17 +10,13 @@ #include "excep.h" #include "corerror.h" #include "classnames.h" -#include "fcall.h" #include "assemblynative.hpp" #include "typeparse.h" #include "reflectioninvocation.h" #include "runtimehandles.h" #include "typestring.h" -typedef InlineFactory, 16> SStringFactory; - -/*static*/ -TypeHandle Attribute::GetTypeForEnum(LPCUTF8 szEnumName, COUNT_T cbEnumName, DomainAssembly* pDomainAssembly) +static TypeHandle GetTypeForEnum(LPCUTF8 szEnumName, COUNT_T cbEnumName, DomainAssembly* pDomainAssembly) { CONTRACTL { @@ -29,7 +25,7 @@ TypeHandle Attribute::GetTypeForEnum(LPCUTF8 szEnumName, COUNT_T cbEnumName, Dom PRECONDITION(cbEnumName); THROWS; GC_TRIGGERS; - MODE_ANY; + MODE_COOPERATIVE; } CONTRACTL_END; @@ -37,12 +33,11 @@ TypeHandle Attribute::GetTypeForEnum(LPCUTF8 szEnumName, COUNT_T cbEnumName, Dom return TypeName::GetTypeReferencedByCustomAttribute(sszEnumName.GetUnicode(), pDomainAssembly->GetAssembly()); } -/*static*/ -HRESULT Attribute::ParseCaType( +static HRESULT ParseCaType( CustomAttributeParser &ca, CaType* pCaType, DomainAssembly* pDomainAssembly, - StackSString* ss) + StackSString* ss = NULL) { WRAPPER_NO_CONTRACT; @@ -50,10 +45,10 @@ HRESULT Attribute::ParseCaType( IfFailGo(::ParseEncodedType(ca, pCaType)); - if (pCaType->tag == SERIALIZATION_TYPE_ENUM || - (pCaType->tag == SERIALIZATION_TYPE_SZARRAY && pCaType->arrayType == SERIALIZATION_TYPE_ENUM )) + if (pCaType->tag == SERIALIZATION_TYPE_ENUM + || (pCaType->tag == SERIALIZATION_TYPE_SZARRAY && pCaType->arrayType == SERIALIZATION_TYPE_ENUM )) { - TypeHandle th = Attribute::GetTypeForEnum(pCaType->szEnumName, pCaType->cEnumName, pDomainAssembly); + TypeHandle th = GetTypeForEnum(pCaType->szEnumName, pCaType->cEnumName, pDomainAssembly); if (!th.IsNull() && th.IsEnum()) { @@ -78,148 +73,12 @@ HRESULT Attribute::ParseCaType( return hr; } -/*static*/ -void Attribute::SetBlittableCaValue(CustomAttributeValue* pVal, CaValue* pCaVal, BOOL* pbAllBlittableCa) -{ - WRAPPER_NO_CONTRACT; - - CorSerializationType type = pCaVal->type.tag; - - pVal->m_type.m_tag = pCaVal->type.tag; - pVal->m_type.m_arrayType = pCaVal->type.arrayType; - pVal->m_type.m_enumType = pCaVal->type.enumType; - pVal->m_rawValue = 0; - - if (type == SERIALIZATION_TYPE_STRING || - type == SERIALIZATION_TYPE_SZARRAY || - type == SERIALIZATION_TYPE_TYPE) - { - *pbAllBlittableCa = FALSE; - } - else - { - // Enum arg -> Object param - if (type == SERIALIZATION_TYPE_ENUM && pCaVal->type.cEnumName) - *pbAllBlittableCa = FALSE; - - pVal->m_rawValue = pCaVal->i8; - } -} - -/*static*/ -void Attribute::SetManagedValue(CustomAttributeManagedValues gc, CustomAttributeValue* pValue) -{ - WRAPPER_NO_CONTRACT; - - CorSerializationType type = pValue->m_type.m_tag; - - if (type == SERIALIZATION_TYPE_TYPE || type == SERIALIZATION_TYPE_STRING) - { - SetObjectReference((OBJECTREF*)&pValue->m_enumOrTypeName, gc.string); - } - else if (type == SERIALIZATION_TYPE_ENUM) - { - SetObjectReference((OBJECTREF*)&pValue->m_type.m_enumName, gc.string); - } - else if (type == SERIALIZATION_TYPE_SZARRAY) - { - SetObjectReference((OBJECTREF*)&pValue->m_value, gc.array); - - if (pValue->m_type.m_arrayType == SERIALIZATION_TYPE_ENUM) - SetObjectReference((OBJECTREF*)&pValue->m_type.m_enumName, gc.string); - } -} - -/*static*/ -CustomAttributeManagedValues Attribute::GetManagedCaValue(CaValue* pCaVal) -{ - WRAPPER_NO_CONTRACT; - - CustomAttributeManagedValues gc; - gc.string = NULL; - gc.array = NULL; - GCPROTECT_BEGIN(gc) - { - CorSerializationType type = pCaVal->type.tag; - - if (type == SERIALIZATION_TYPE_ENUM) - { - gc.string = StringObject::NewString(pCaVal->type.szEnumName, pCaVal->type.cEnumName); - } - else if (type == SERIALIZATION_TYPE_STRING) - { - gc.string = NULL; - - if (pCaVal->str.pStr) - gc.string = StringObject::NewString(pCaVal->str.pStr, pCaVal->str.cbStr); - } - else if (type == SERIALIZATION_TYPE_TYPE) - { - gc.string = StringObject::NewString(pCaVal->str.pStr, pCaVal->str.cbStr); - } - else if (type == SERIALIZATION_TYPE_SZARRAY) - { - CorSerializationType arrayType = pCaVal->type.arrayType; - ULONG length = pCaVal->arr.length; - BOOL bAllBlittableCa = arrayType != SERIALIZATION_TYPE_ENUM; - - if (arrayType == SERIALIZATION_TYPE_ENUM) - gc.string = StringObject::NewString(pCaVal->type.szEnumName, pCaVal->type.cEnumName); - - if (length != (ULONG)-1) - { - gc.array = (CaValueArrayREF)AllocateSzArray(TypeHandle(CoreLibBinder::GetClass(CLASS__CUSTOM_ATTRIBUTE_ENCODED_ARGUMENT)).MakeSZArray(), length); - CustomAttributeValue* pValues = gc.array->GetDirectPointerToNonObjectElements(); - - for (COUNT_T i = 0; i < length; i ++) - Attribute::SetBlittableCaValue(&pValues[i], &pCaVal->arr[i], &bAllBlittableCa); - - if (!bAllBlittableCa) - { - for (COUNT_T i = 0; i < length; i ++) - { - CustomAttributeManagedValues managedCaValue = Attribute::GetManagedCaValue(&pCaVal->arr[i]); - Attribute::SetManagedValue( - managedCaValue, - &gc.array->GetDirectPointerToNonObjectElements()[i]); - } - } - } - } - } - GCPROTECT_END(); - return gc; -} - -/*static*/ -HRESULT Attribute::ParseAttributeArgumentValues( - void* pCa, - INT32 cCa, - CaValueArrayFactory* pCaValueArrayFactory, - CaArg* pCaArgs, - COUNT_T cArgs, - CaNamedArg* pCaNamedArgs, - COUNT_T cNamedArgs, - DomainAssembly* pDomainAssembly) -{ - WRAPPER_NO_CONTRACT; - - HRESULT hr = S_OK; - CustomAttributeParser cap(pCa, cCa); - - IfFailGo(Attribute::ParseCaCtorArgs(cap, pCaArgs, cArgs, pCaValueArrayFactory, pDomainAssembly)); - IfFailGo(Attribute::ParseCaNamedArgs(cap, pCaNamedArgs, cNamedArgs, pCaValueArrayFactory, pDomainAssembly)); - -ErrExit: - return hr; -} - //--------------------------------------------------------------------------------------- // // Helper to parse the values for the ctor argument list and the named argument list. // -HRESULT Attribute::ParseCaValue( +static HRESULT ParseCaValue( CustomAttributeParser &ca, CaValue* pCaArg, CaType* pCaParam, @@ -240,7 +99,7 @@ HRESULT Attribute::ParseCaValue( CaType elementType; if (pCaParam->tag == SERIALIZATION_TYPE_TAGGED_OBJECT) - IfFailGo(Attribute::ParseCaType(ca, &pCaArg->type, pDomainAssembly)); + IfFailGo(ParseCaType(ca, &pCaArg->type, pDomainAssembly)); else pCaArg->type = *pCaParam; @@ -296,7 +155,7 @@ HRESULT Attribute::ParseCaValue( elementType.Init(pCaArg->type.arrayType, SERIALIZATION_TYPE_UNDEFINED, pCaArg->type.enumType, pCaArg->type.szEnumName, pCaArg->type.cEnumName); for (ULONG i = 0; i < pCaArg->arr.length; i++) - IfFailGo(Attribute::ParseCaValue(ca, &*pCaArg->arr.pSArray->Append(), &elementType, pCaValueArrayFactory, pDomainAssembly)); + IfFailGo(ParseCaValue(ca, &*pCaArg->arr.pSArray->Append(), &elementType, pCaValueArrayFactory, pDomainAssembly)); break; @@ -310,8 +169,7 @@ HRESULT Attribute::ParseCaValue( return hr; } -/*static*/ -HRESULT Attribute::ParseCaCtorArgs( +static HRESULT ParseCaCtorArgs( CustomAttributeParser &ca, CaArg* pArgs, ULONG cArgs, @@ -333,7 +191,7 @@ HRESULT Attribute::ParseCaCtorArgs( for (ix=0; ixval, &pArg->type, pCaValueArrayFactory, pDomainAssembly)); + IfFailGo(ParseCaValue(ca, &pArg->val, &pArg->type, pCaValueArrayFactory, pDomainAssembly)); } ErrExit: @@ -347,8 +205,7 @@ HRESULT Attribute::ParseCaCtorArgs( // 2. It Compares the enum type name with that of the loaded enum type, not the one in the CA record. // -/*static*/ -HRESULT Attribute::ParseCaNamedArgs( +static HRESULT ParseCaNamedArgs( CustomAttributeParser &ca, CaNamedArg *pNamedParams, ULONG cNamedParams, @@ -386,7 +243,7 @@ HRESULT Attribute::ParseCaNamedArgs( // Get argument type information CaType* pNamedArgType = &namedArg.type; StackSString ss; - IfFailGo(Attribute::ParseCaType(ca, pNamedArgType, pDomainAssembly, &ss)); + IfFailGo(ParseCaType(ca, pNamedArgType, pDomainAssembly, &ss)); LPCSTR szLoadedEnumName = NULL; @@ -462,7 +319,7 @@ HRESULT Attribute::ParseCaNamedArgs( IfFailGo(PostError(META_E_CA_REPEATED_ARG, namedArg.cName, namedArg.szName)); } - IfFailGo(Attribute::ParseCaValue(ca, &pNamedParams[ixParam].val, &namedArg.type, pCaValueArrayFactory, pDomainAssembly)); + IfFailGo(ParseCaValue(ca, &pNamedParams[ixParam].val, &namedArg.type, pCaValueArrayFactory, pDomainAssembly)); } ErrExit: @@ -470,185 +327,28 @@ HRESULT Attribute::ParseCaNamedArgs( } /*static*/ -HRESULT Attribute::InitCaType(CustomAttributeType* pType, Factory* pSstringFactory, CaType* pCaType) +HRESULT Attribute::ParseAttributeArgumentValues( + void* pCa, + INT32 cCa, + CaValueArrayFactory* pCaValueArrayFactory, + CaArg* pCaArgs, + COUNT_T cArgs, + CaNamedArg* pCaNamedArgs, + COUNT_T cNamedArgs, + DomainAssembly* pDomainAssembly) { - CONTRACTL { - THROWS; - PRECONDITION(CheckPointer(pType)); - PRECONDITION(CheckPointer(pSstringFactory)); - PRECONDITION(CheckPointer(pCaType)); - } CONTRACTL_END; + WRAPPER_NO_CONTRACT; HRESULT hr = S_OK; + CustomAttributeParser cap(pCa, cCa); - SString* psszName = NULL; - - IfNullGo(psszName = pSstringFactory->Create()); - - psszName->Set(pType->m_enumName == NULL ? NULL : pType->m_enumName->GetBuffer()); - - pCaType->Init( - pType->m_tag, - pType->m_arrayType, - pType->m_enumType, - psszName->GetUTF8(), - (ULONG)psszName->GetCount()); + IfFailGo(ParseCaCtorArgs(cap, pCaArgs, cArgs, pCaValueArrayFactory, pDomainAssembly)); + IfFailGo(ParseCaNamedArgs(cap, pCaNamedArgs, cNamedArgs, pCaValueArrayFactory, pDomainAssembly)); ErrExit: return hr; } -FCIMPL5(VOID, Attribute::ParseAttributeArguments, void* pCa, INT32 cCa, - CaArgArrayREF* ppCustomAttributeArguments, - CaNamedArgArrayREF* ppCustomAttributeNamedArguments, - AssemblyBaseObject* pAssemblyUNSAFE) -{ - FCALL_CONTRACT; - - ASSEMBLYREF refAssembly = (ASSEMBLYREF)ObjectToOBJECTREF(pAssemblyUNSAFE); - - HELPER_METHOD_FRAME_BEGIN_1(refAssembly) - { - DomainAssembly *pDomainAssembly = refAssembly->GetDomainAssembly(); - - struct - { - CustomAttributeArgument* pArgs; - CustomAttributeNamedArgument* pNamedArgs; - } gc; - - gc.pArgs = NULL; - gc.pNamedArgs = NULL; - - HRESULT hr = S_OK; - - GCPROTECT_BEGININTERIOR(gc); - - BOOL bAllBlittableCa = TRUE; - COUNT_T cArgs = 0; - COUNT_T cNamedArgs = 0; - CaArg* pCaArgs = NULL; - CaNamedArg* pCaNamedArgs = NULL; -#ifdef __GNUC__ - // When compiling under GCC we have to use the -fstack-check option to ensure we always spot stack - // overflow. But this option is intolerant of locals growing too large, so we have to cut back a bit - // on what we can allocate inline here. Leave the Windows versions alone to retain the perf benefits - // since we don't have the same constraints. - NewHolder pCaValueArrayFactory = new InlineFactory, 4>(); - InlineFactory sstringFactory; -#else // __GNUC__ - - // Preallocate 4 elements in each of the following factories for optimal performance. - // 4 is enough for 4 typed args or 2 named args which are enough for 99% of the cases. - - // SArray is only needed if a argument is an array, don't preallocate any memory as arrays are rare. - - // Need one per (ctor or named) arg + one per array element - InlineFactory, 4> caValueArrayFactory; - InlineFactory, 4> *pCaValueArrayFactory = &caValueArrayFactory; - - // Need one SString per ctor arg and two per named arg - InlineFactory sstringFactory; -#endif // __GNUC__ - - cArgs = (*ppCustomAttributeArguments)->GetNumComponents(); - - if (cArgs) - { - gc.pArgs = (*ppCustomAttributeArguments)->GetDirectPointerToNonObjectElements(); - - size_t size = sizeof(CaArg) * cArgs; - if ((size / sizeof(CaArg)) != cArgs) // uint over/underflow - IfFailGo(E_INVALIDARG); - pCaArgs = (CaArg*)_alloca(size); - - for (COUNT_T i = 0; i < cArgs; i ++) - { - CaType caType; - IfFailGo(Attribute::InitCaType(&gc.pArgs[i].m_type, &sstringFactory, &caType)); - - pCaArgs[i].Init(caType); - } - } - - cNamedArgs = (*ppCustomAttributeNamedArguments)->GetNumComponents(); - - if (cNamedArgs) - { - gc.pNamedArgs = (*ppCustomAttributeNamedArguments)->GetDirectPointerToNonObjectElements(); - - size_t size = sizeof(CaNamedArg) * cNamedArgs; - if ((size / sizeof(CaNamedArg)) != cNamedArgs) // uint over/underflow - IfFailGo(E_INVALIDARG); - pCaNamedArgs = (CaNamedArg*)_alloca(size); - - for (COUNT_T i = 0; i < cNamedArgs; i ++) - { - CustomAttributeNamedArgument* pNamedArg = &gc.pNamedArgs[i]; - - CaType caType; - IfFailGo(Attribute::InitCaType(&pNamedArg->m_type, &sstringFactory, &caType)); - - SString* psszName = NULL; - IfNullGo(psszName = sstringFactory.Create()); - - psszName->Set(pNamedArg->m_argumentName->GetBuffer()); - - pCaNamedArgs[i].Init( - psszName->GetUTF8(), - pNamedArg->m_propertyOrField, - caType); - } - } - - // This call maps the named parameters (fields and arguments) and ctor parameters with the arguments in the CA record - // and retrieve their values. - IfFailGo(Attribute::ParseAttributeArgumentValues(pCa, cCa, pCaValueArrayFactory, pCaArgs, cArgs, pCaNamedArgs, cNamedArgs, pDomainAssembly)); - - for (COUNT_T i = 0; i < cArgs; i ++) - Attribute::SetBlittableCaValue(&gc.pArgs[i].m_value, &pCaArgs[i].val, &bAllBlittableCa); - - for (COUNT_T i = 0; i < cNamedArgs; i ++) - Attribute::SetBlittableCaValue(&gc.pNamedArgs[i].m_value, &pCaNamedArgs[i].val, &bAllBlittableCa); - - if (!bAllBlittableCa) - { - for (COUNT_T i = 0; i < cArgs; i ++) - { - CustomAttributeManagedValues managedCaValue = Attribute::GetManagedCaValue(&pCaArgs[i].val); - Attribute::SetManagedValue(managedCaValue, &(gc.pArgs[i].m_value)); - } - - for (COUNT_T i = 0; i < cNamedArgs; i++) - { - CustomAttributeManagedValues managedCaValue = Attribute::GetManagedCaValue(&pCaNamedArgs[i].val); - Attribute::SetManagedValue(managedCaValue, &(gc.pNamedArgs[i].m_value)); - } - } - - ErrExit: - - ; // Need empty statement to get GCPROTECT_END below to work. - - GCPROTECT_END(); - - - if (hr != S_OK) - { - if ((hr == E_OUTOFMEMORY) || (hr == NTE_NO_MEMORY)) - { - COMPlusThrow(kOutOfMemoryException); - } - else - { - COMPlusThrow(kCustomAttributeFormatException); - } - } - } - HELPER_METHOD_FRAME_END(); -} -FCIMPLEND - FCIMPL6(LPVOID, COMCustomAttribute::CreateCaObject, ReflectModuleBaseObject* pAttributedModuleUNSAFE, ReflectClassBaseObject* pCaTypeUNSAFE, ReflectMethodObject *pMethodUNSAFE, BYTE** ppBlob, BYTE* pEndBlob, INT32* pcNamedArgs) { FCALL_CONTRACT; diff --git a/src/coreclr/vm/customattribute.h b/src/coreclr/vm/customattribute.h index 6d4282d8f52ab7..14ce07c785d5c8 100644 --- a/src/coreclr/vm/customattribute.h +++ b/src/coreclr/vm/customattribute.h @@ -8,102 +8,11 @@ #include "fcall.h" #include "../md/compiler/custattr.h" -struct CustomAttributeType; -struct CustomAttributeValue; -struct CustomAttributeArgument; -struct CustomAttributeNamedArgument; - -typedef Array CaArgArray; -typedef Array CaNamedArgArray; -typedef Array CaValueArray; - -typedef DPTR(CaArgArray) PTR_CaArgArray; -typedef DPTR(CaNamedArgArray) PTR_CaNamedArgArray; -typedef DPTR(CaValueArray) PTR_CaValueArray; - -#ifdef USE_CHECKED_OBJECTREFS -typedef REF CaArgArrayREF; -typedef REF CaNamedArgArrayREF; -typedef REF CaValueArrayREF; -#else -typedef PTR_CaArgArray CaArgArrayREF; -typedef PTR_CaNamedArgArray CaNamedArgArrayREF; -typedef PTR_CaValueArray CaValueArrayREF; -#endif - - -#include -struct CustomAttributeType -{ - STRINGREF m_enumName; - CorSerializationType m_tag; - CorSerializationType m_enumType; - CorSerializationType m_arrayType; - CorSerializationType m_padding; -}; - -struct CustomAttributeValue -{ -#ifdef HOST_64BIT - // refs come before longs on win64 - CaValueArrayREF m_value; - STRINGREF m_enumOrTypeName; - INT64 m_rawValue; -#else - // longs come before refs on x86 - INT64 m_rawValue; - CaValueArrayREF m_value; - STRINGREF m_enumOrTypeName; -#endif - CustomAttributeType m_type; -#if defined(FEATURE_64BIT_ALIGNMENT) - DWORD m_padding; -#endif -}; - -struct CustomAttributeArgument -{ - CustomAttributeType m_type; -#if (!defined(HOST_64BIT) && (DATA_ALIGNMENT > 4)) || defined(FEATURE_64BIT_ALIGNMENT) - DWORD m_padding; -#endif - CustomAttributeValue m_value; -}; - -struct CustomAttributeNamedArgument -{ - STRINGREF m_argumentName; - CorSerializationType m_propertyOrField; - CorSerializationType m_padding; -#if !defined(HOST_64BIT) && (DATA_ALIGNMENT > 4) - DWORD m_padding2; -#endif - CustomAttributeType m_type; -#if !defined(HOST_64BIT) && (DATA_ALIGNMENT > 4) - DWORD m_padding3; -#endif - CustomAttributeValue m_value; -}; -#include - - -typedef struct { - STRINGREF string; - CaValueArrayREF array; -} CustomAttributeManagedValues; - typedef Factory< SArray > CaValueArrayFactory; class Attribute { public: - static FCDECL5(VOID, ParseAttributeArguments, - void* pCa, - INT32 cCa, - CaArgArrayREF* ppCustomAttributeArguments, - CaNamedArgArrayREF* ppCustomAttributeNamedArguments, - AssemblyBaseObject* pAssemblyUNSAFE); - static HRESULT ParseAttributeArgumentValues( void* pCa, INT32 cCa, @@ -113,55 +22,6 @@ class Attribute CaNamedArg* pCaNamedArgs, COUNT_T cNamedArgs, DomainAssembly* pDomainAssembly); - -private: - static HRESULT ParseCaValue( - CustomAttributeParser &ca, - CaValue* pCaArg, - CaType* pCaParam, - CaValueArrayFactory* pCaValueArrayFactory, - DomainAssembly* pDomainAssembly); - - static HRESULT ParseCaCtorArgs( - CustomAttributeParser &ca, - CaArg* pArgs, - ULONG cArgs, - CaValueArrayFactory* pCaValueArrayFactory, - DomainAssembly* pDomainAssembly); - - static HRESULT ParseCaNamedArgs( - CustomAttributeParser &ca, // The Custom Attribute blob. - CaNamedArg *pNamedParams, // Array of argument descriptors. - ULONG cNamedParams, - CaValueArrayFactory* pCaValueArrayFactory, - DomainAssembly* pDomainAssembly); - - static HRESULT InitCaType( - CustomAttributeType* pType, - Factory* pSstringFactory, - CaType* pCaType); - - static HRESULT ParseCaType( - CustomAttributeParser &ca, - CaType* pCaType, - DomainAssembly* pDomainAssembly, - StackSString* ss = NULL); - - static TypeHandle GetTypeForEnum( - LPCUTF8 szEnumName, - COUNT_T cbEnumName, - DomainAssembly* pDomainAssembly); - - static void SetBlittableCaValue( - CustomAttributeValue* pVal, - CaValue* pCaVal, - BOOL* pbAllBlittableCa); - - static void SetManagedValue( - CustomAttributeManagedValues gc, - CustomAttributeValue* pValue); - - static CustomAttributeManagedValues GetManagedCaValue(CaValue* pCaVal); }; class COMCustomAttribute diff --git a/src/coreclr/vm/ecalllist.h b/src/coreclr/vm/ecalllist.h index e6b1ae38cd77bc..96d0316c48909e 100644 --- a/src/coreclr/vm/ecalllist.h +++ b/src/coreclr/vm/ecalllist.h @@ -251,10 +251,6 @@ FCFuncStart(gCOMModuleHandleFuncs) FCFuncElement("GetMDStreamVersion", ModuleHandle::GetMDStreamVersion) FCFuncEnd() -FCFuncStart(gCustomAttributeEncodedArgument) - FCFuncElement("ParseAttributeArguments", Attribute::ParseAttributeArguments) -FCFuncEnd() - FCFuncStart(gCOMCustomAttributeFuncs) FCFuncElement("_ParseAttributeUsageAttribute", COMCustomAttribute::ParseAttributeUsageAttribute) FCFuncElement("_CreateCaObject", COMCustomAttribute::CreateCaObject) @@ -404,7 +400,6 @@ FCFuncStart(gGCFrameRegistration) FCFuncEnd() FCFuncStart(gGCInterfaceFuncs) - FCFuncElement("GetGenerationWR", GCInterface::GetGenerationWR) FCFuncElement("_RegisterForFullGCNotification", GCInterface::RegisterForFullGCNotification) FCFuncElement("_CancelFullGCNotification", GCInterface::CancelFullGCNotification) FCFuncElement("_CollectionCount", GCInterface::CollectionCount) @@ -613,7 +608,6 @@ FCClassElement("CastHelpers", "System.Runtime.CompilerServices", gCastHelpers) FCClassElement("ComAwareWeakReference", "System", gComAwareWeakReferenceFuncs) FCClassElement("CompatibilitySwitch", "System.Runtime.Versioning", gCompatibilitySwitchFuncs) FCClassElement("CustomAttribute", "System.Reflection", gCOMCustomAttributeFuncs) -FCClassElement("CustomAttributeEncodedArgument", "System.Reflection", gCustomAttributeEncodedArgument) FCClassElement("Debugger", "System.Diagnostics", gDiagnosticsDebugger) FCClassElement("Delegate", "System", gDelegateFuncs) FCClassElement("DependentHandle", "System.Runtime", gDependentHandleFuncs) diff --git a/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx b/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx index f32b66df95e796..089418e78f4c36 100644 --- a/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx +++ b/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx @@ -274,6 +274,12 @@ Binary format of the specified custom attribute was invalid. + + Known custom attribute named arg not recognized. + + + Known custom attribute blob has repeated named argument. + A datatype misalignment was detected in a load or store instruction. diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/AttributeTests.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/AttributeTests.cs index 6774195fa52ff7..1cc7e3ee6c6e4a 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/AttributeTests.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/AttributeTests.cs @@ -167,7 +167,14 @@ public static void StringArgument_InvalidCodeUnits_FallbackUsed() string stringArg = cad.ConstructorArguments[0].Value as string; Assert.NotNull(stringArg); - Assert.Equal("\uFFFD\uFFFD", stringArg); + + // Validate that each character is 'invalid'. + // The runtimes are inconsistent with respect to conversion + // failure modes so we just validate each character. + foreach (char c in stringArg) + { + Assert.Equal('\uFFFD', c); + } } public static IEnumerable Equals_TestData()