Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix more bugs found with ILVerify #98393

Merged
merged 3 commits into from
Feb 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -68,13 +68,6 @@ public override object Invoke(object? obj, BindingFlags invokeAttr, Binder? bind
throw new NotSupportedException();
}
public override CallingConventions CallingConvention => _method.CallingConvention;
#if !MONO
public override MethodInfo GetGenericMethodDefinition() { return _method; }
public override bool IsGenericMethodDefinition => _method.IsGenericMethodDefinition;
public override Type[] GetGenericArguments()
{
return _method.GetGenericArguments();
}
public override bool ContainsGenericParameters
{
get
Expand All @@ -101,6 +94,14 @@ public override bool ContainsGenericParameters
return false;
}
}
#if !MONO
public override MethodInfo GetGenericMethodDefinition() { return _method; }
public override bool IsGenericMethodDefinition => _method.IsGenericMethodDefinition;
public override Type[] GetGenericArguments()
{
return _method.GetGenericArguments();
}

[RequiresUnreferencedCode("If some of the generic arguments are annotated (either with DynamicallyAccessedMembersAttribute, or generic constraints), trimming can't validate that the requirements of those annotations are met.")]
public override MethodInfo MakeGenericMethod(params Type[] typeArgs)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,21 @@ protected override void SetSignatureCore(Type? returnType, Type[]? returnTypeReq
public override int MetadataToken => _handle == default ? 0 : MetadataTokens.GetToken(_handle);
public override RuntimeMethodHandle MethodHandle => throw new NotSupportedException(SR.NotSupported_DynamicModule);
public override Type? ReflectedType => DeclaringType;
public override ParameterInfo ReturnParameter { get => throw new NotImplementedException(); }
public override ParameterInfo ReturnParameter
{
get
{
if (_parameterBuilders == null || _parameterBuilders[0] == null)
{
return new ParameterInfoWrapper(new ParameterBuilderImpl(this, 0, ParameterAttributes.Retval, null), _returnType);
}
else
{
return new ParameterInfoWrapper(_parameterBuilders[0], _returnType);
}
}
}

public override Type ReturnType => _returnType;
public override ICustomAttributeProvider ReturnTypeCustomAttributes { get => throw new NotImplementedException(); }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -538,6 +538,7 @@ private EntityHandle GetMemberReferenceHandle(MemberInfo memberInfo)
MetadataSignatureHelper.GetFieldSignature(field.FieldType, field.GetRequiredCustomModifiers(), field.GetOptionalCustomModifiers(), this));
break;
case ConstructorInfo ctor:
ctor = (ConstructorInfo)GetOriginalMemberIfConstructedType(ctor);
memberHandle = AddMemberReference(ctor.Name, GetTypeHandle(memberInfo.DeclaringType!), MetadataSignatureHelper.GetConstructorSignature(ctor.GetParameters(), this));
break;
case MethodInfo method:
Expand Down Expand Up @@ -606,8 +607,9 @@ internal static SignatureCallingConvention GetSignatureConvention(CallingConvent
private static MemberInfo GetOriginalMemberIfConstructedType(MethodBase methodBase)
{
Type declaringType = methodBase.DeclaringType!;
if (declaringType.IsConstructedGenericType && !methodBase.ContainsGenericParameters &&
declaringType.GetGenericTypeDefinition() is not TypeBuilderImpl)
if (declaringType.IsConstructedGenericType &&
declaringType.GetGenericTypeDefinition() is not TypeBuilderImpl &&
!ContainsNotBakedTypeBuilder(declaringType.GetGenericArguments()))
{
return declaringType.GetGenericTypeDefinition().GetMemberWithSameMetadataDefinitionAs(methodBase);
}
Expand Down Expand Up @@ -890,14 +892,14 @@ private EntityHandle GetHandleForMember(MemberInfo member)
}

private static bool IsConstructedFromNotBakedTypeBuilder(Type type) => type.IsConstructedGenericType &&
(type.GetGenericTypeDefinition() is TypeBuilderImpl tb && tb._handle == default ||
(type.GetGenericTypeDefinition() is TypeBuilderImpl ||
ContainsNotBakedTypeBuilder(type.GetGenericArguments()));

private static bool ContainsNotBakedTypeBuilder(Type[] genericArguments)
{
foreach (Type type in genericArguments)
{
if (type is TypeBuilderImpl tb && tb._handle == default)
if (type is TypeBuilderImpl || type is GenericTypeParameterBuilderImpl)
{
return true;
}
Expand Down Expand Up @@ -964,8 +966,8 @@ internal EntityHandle TryGetMethodHandle(MethodInfo method)
private static bool IsArrayMethodFromNotBakedTypeBuilder(MethodInfo method) => method is ArrayMethod arrayMethod &&
arrayMethod.DeclaringType!.GetElementType() is TypeBuilderImpl tb && tb._handle == default;

private static bool IsConstructedMethodFromNotBakedMethodBuilder(MethodInfo method) =>
method.IsConstructedGenericMethod && method.GetGenericMethodDefinition() is MethodBuilderImpl mb && mb._handle == default;
private static bool IsConstructedMethodFromNotBakedMethodBuilder(MethodInfo method) => method.IsConstructedGenericMethod &&
(method.GetGenericMethodDefinition() is MethodBuilderImpl mb && mb._handle == default || ContainsNotBakedTypeBuilder(method.GetGenericArguments()));

internal EntityHandle TryGetMethodHandle(MethodInfo method, Type[] optionalParameterTypes)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using Xunit;

namespace System.Reflection.Emit.Tests
Expand Down Expand Up @@ -95,5 +96,68 @@ public void Set_WhenTypeAlreadyCreated_ThrowsInvalidOperationException()
Assert.Throws<InvalidOperationException>(() => eventBuilder.AddOtherMethod(method));
Assert.Throws<InvalidOperationException>(() => eventBuilder.SetCustomAttribute(customAttrBuilder));
}

[Fact]
public void ReferenceEventInIL()
{
using (TempFile file = TempFile.Create())
{
AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder type);
TypeBuilder delegateType = ab.GetDynamicModule("MyModule").DefineType("OnMissingString", TypeAttributes.Public | TypeAttributes.Sealed, typeof(MulticastDelegate));
delegateType.DefineMethod("Invoke", MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual,
typeof(void), [typeof(string)]).SetImplementationFlags(MethodImplAttributes.Runtime);
delegateType.DefineMethod("BeginInvoke", MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual,
typeof(IAsyncResult), [typeof(string), typeof(AsyncCallback), typeof(object)]).SetImplementationFlags(MethodImplAttributes.Runtime);
delegateType.DefineMethod("EndInvoke", MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual,
typeof(void), [typeof(IAsyncResult)]).SetImplementationFlags(MethodImplAttributes.Runtime);
delegateType.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, [typeof(object), typeof(IntPtr)]).
SetImplementationFlags(MethodImplAttributes.Runtime);
MethodInfo combineMethod = typeof(Delegate).GetMethod("Combine", [typeof(Delegate), typeof(Delegate)]);
MethodInfo interlockedGenericMethod = typeof(Interlocked).GetMethods(BindingFlags.Public | BindingFlags.Static).
Where(m => m.Name == "CompareExchange" && m.IsGenericMethodDefinition && m.GetGenericArguments().Length == 1).First().MakeGenericMethod(delegateType);
EventBuilder eventBuilder = type.DefineEvent("MissingString", EventAttributes.SpecialName, delegateType);
FieldBuilder field = type.DefineField("MissingString", delegateType, FieldAttributes.Private);
MethodBuilder addMethod = type.DefineMethod("add_MissingString", MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, null, [delegateType]);
ILGenerator addIL = addMethod.GetILGenerator();
addIL.DeclareLocal(delegateType);
addIL.DeclareLocal(delegateType);
addIL.DeclareLocal(delegateType);
Label loop = addIL.DefineLabel();
addIL.Emit(OpCodes.Ldarg_0);
addIL.Emit(OpCodes.Ldfld, field);
addIL.Emit(OpCodes.Stloc_0);
addIL.MarkLabel(loop);
addIL.Emit(OpCodes.Ldloc_0);
addIL.Emit(OpCodes.Stloc_1);
addIL.Emit(OpCodes.Ldloc_1);
addIL.Emit(OpCodes.Ldarg_1);
addIL.Emit(OpCodes.Call, combineMethod);
addIL.Emit(OpCodes.Castclass, delegateType);
addIL.Emit(OpCodes.Stloc_2);
addIL.Emit(OpCodes.Ldarg_0);
addIL.Emit(OpCodes.Ldflda, field);
addIL.Emit(OpCodes.Ldloc_2);
addIL.Emit(OpCodes.Ldloc_1);
addIL.Emit(OpCodes.Call, interlockedGenericMethod);
addIL.Emit(OpCodes.Stloc_0);
addIL.Emit(OpCodes.Ldloc_0);
addIL.Emit(OpCodes.Ldloc_1);
addIL.Emit(OpCodes.Bne_Un_S, loop);
addIL.Emit(OpCodes.Ret);
eventBuilder.SetAddOnMethod(addMethod);

delegateType.CreateType();
type.CreateType();
ab.Save(file.Path);

using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver()))
{
Assembly assemblyFromDisk = mlc.LoadFromAssemblyPath(file.Path);
Type typeFromDisk = assemblyFromDisk.Modules.First().GetType("MyType");
EventInfo eventFromDisk = typeFromDisk.GetEvent("MissingString");
Assert.Equal(addMethod.Name, eventFromDisk.AddMethod.Name);
Assert.Equal(delegateType.FullName, eventFromDisk.EventHandlerType.FullName); }
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2503,5 +2503,34 @@ public void ReferenceNestedGenericTypeWithConstructedTypeBuilderParameterInIL()
}
}
}

[Fact]
public void ConstructorOfGenericTypeReferencedCorrectly()
{
using (TempFile file = TempFile.Create())
{
AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder type);
FieldBuilder field = type.DefineField("Field", typeof(int?), FieldAttributes.Public);
ConstructorBuilder ctor = type.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, Type.EmptyTypes);
ILGenerator ctorIL = ctor.GetILGenerator();
ctorIL.Emit(OpCodes.Ldarg_0);
ctorIL.Emit(OpCodes.Call, typeof(object).GetConstructor(Type.EmptyTypes));
ctorIL.Emit(OpCodes.Ldarg_0);
ctorIL.Emit(OpCodes.Ldc_I4_1);
ctorIL.Emit(OpCodes.Newobj, typeof(int?).GetConstructor([typeof(int)]));
ctorIL.Emit(OpCodes.Stfld, field);
ctorIL.Emit(OpCodes.Ret);
type.CreateType();
ab.Save(file.Path);

TestAssemblyLoadContext tlc = new TestAssemblyLoadContext();
Type typeFromDisk = tlc.LoadFromAssemblyPath(file.Path).GetType("MyType");
FieldInfo fieldFromDisk = typeFromDisk.GetField("Field");
object obj = Activator.CreateInstance(typeFromDisk);
Assert.Equal(typeof(int?), fieldFromDisk.FieldType);
Assert.Equal(1, fieldFromDisk.GetValue(obj));
tlc.Unload();
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -892,5 +892,22 @@ public void AbstractBaseMethodImplementationReturnsDifferentType()
Assert.IsType(typeFromDisk, obj);
}
}

[Fact]
public void TestContainsGenericParametersOnMethodCtorOfConstructedGenericType()
{
AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder tb);
GenericTypeParameterBuilder[] typeParameters = tb.DefineGenericParameters("T");
ConstructorBuilder constructorBuilder = tb.DefineDefaultConstructor(MethodAttributes.Public);
MethodBuilder methodBuilder = tb.DefineMethod("Method", MethodAttributes.Public);

Type instantiatedTypeBuilder1 = tb.MakeGenericType(typeof(List<>).GetGenericArguments()[0]);
Assert.True(TypeBuilder.GetConstructor(instantiatedTypeBuilder1, constructorBuilder).ContainsGenericParameters);
Assert.True(TypeBuilder.GetMethod(instantiatedTypeBuilder1, methodBuilder).ContainsGenericParameters);

Type instantiatedTypeBuilder2 = tb.MakeGenericType(typeof(int));
Assert.False(TypeBuilder.GetConstructor(instantiatedTypeBuilder2, constructorBuilder).ContainsGenericParameters);
Assert.False(TypeBuilder.GetMethod(instantiatedTypeBuilder2, methodBuilder).ContainsGenericParameters);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -606,6 +606,49 @@ public void SaveMultipleGenericTypeParametersToEnsureSortingWorks()
}
}
}

[Fact]
public void MethodBuilderGetParametersReturnParameterTest()
{
AssemblyBuilder assemblyBuilder = AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder type);
MethodBuilder method1 = type.DefineMethod("Method1", MethodAttributes.Public, typeof(long), [typeof(int), typeof(string)]);
MethodBuilder method2 = type.DefineMethod("Method2", MethodAttributes.Static);
MethodBuilder method3 = type.DefineMethod("Method1", MethodAttributes.Public, typeof(int), [typeof(string)]);
method1.DefineParameter(0, ParameterAttributes.Retval, null);
method1.DefineParameter(1, ParameterAttributes.None, "index");
method1.DefineParameter(2, ParameterAttributes.Out, "outParam");
ParameterBuilder pb = method3.DefineParameter(1, ParameterAttributes.Optional, "name");
pb.SetConstant("defaultName");
//type.CreateType();

ParameterInfo[] params1 = method1.GetParameters();
Assert.Equal(2, params1.Length);
Assert.Equal("index", params1[0].Name);
Assert.Equal(typeof(int), params1[0].ParameterType);
Assert.Equal("outParam", params1[1].Name);
Assert.Equal(typeof(string), params1[1].ParameterType);
Assert.Equal(ParameterAttributes.Out, params1[1].Attributes);
Assert.True(params1[1].IsOut);
Assert.Equal(typeof(long), method1.ReturnParameter.ParameterType);
Assert.Null(method1.ReturnParameter.Name);
Assert.True(method1.ReturnParameter.IsRetval);

Assert.Empty(method2.GetParameters());
Assert.Equal(typeof(void), method2.ReturnParameter.ParameterType);
Assert.Null(method2.ReturnParameter.Name);
Assert.True(method2.ReturnParameter.IsRetval);

ParameterInfo[] params3 = method3.GetParameters();
Assert.Equal(1, params3.Length);
Assert.Equal("name", params3[0].Name);
Assert.Equal(typeof(string), params3[0].ParameterType);
Assert.True(params3[0].HasDefaultValue);
Assert.Equal("defaultName", params3[0].DefaultValue);

Assert.Equal(typeof(int), method3.ReturnParameter.ParameterType);
Assert.Null(method3.ReturnParameter.Name);
Assert.True(method3.ReturnParameter.IsRetval);
}
}

// Test Types
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,25 +66,6 @@ public override Type[] GetGenericArguments()
return result;
}

public override bool ContainsGenericParameters
{
get
{
if (_method.ContainsGenericParameters)
return true;
if (!_method.IsGenericMethodDefinition)
throw new NotSupportedException();
if (_typeArguments == null)
return true;
foreach (Type t in _typeArguments)
{
if (t.ContainsGenericParameters)
return true;
}
return false;
}
}

public override bool IsGenericMethodDefinition => _method.IsGenericMethodDefinition && _typeArguments == null;

public override MethodInfo GetGenericMethodDefinition() { return _genericMethodDefinition ?? _method; }
Expand Down