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

Add ImportAsOperand to fix DynamicMethodBodyReader #553

Closed
wants to merge 2 commits into from
Closed
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
29 changes: 16 additions & 13 deletions src/DotNet/Emit/DynamicMethodBodyReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -420,16 +420,16 @@ public MethodDef GetMethod() {
protected override string ReadInlineString(Instruction instr) => ReadToken(reader.ReadUInt32()) as string ?? string.Empty;

/// <inheritdoc/>
protected override ITokenOperand ReadInlineTok(Instruction instr) => ReadToken(reader.ReadUInt32()) as ITokenOperand;
protected override ITokenOperand ReadInlineTok(Instruction instr) => ReadToken(reader.ReadUInt32(), true) as ITokenOperand;

/// <inheritdoc/>
protected override ITypeDefOrRef ReadInlineType(Instruction instr) => ReadToken(reader.ReadUInt32()) as ITypeDefOrRef;

object ReadToken(uint token) {
object ReadToken(uint token, bool ldtoken = false) {
uint rid = token & 0x00FFFFFF;
switch (token >> 24) {
case 0x02:
return ImportType(rid);
return ImportType(rid, ldtoken);

case 0x04:
return ImportField(rid);
Expand Down Expand Up @@ -458,22 +458,22 @@ IMethod ImportMethod(uint rid) {
if ((options & DynamicMethodBodyReaderOptions.UnknownDeclaringType) != 0) {
// Sometimes it's a generic type but obj != `GenericMethodInfo`, so pass in 'default' and the
// runtime will try to figure out the declaring type. https://github.com/0xd4d/dnlib/issues/298
return importer.Import(SR.MethodBase.GetMethodFromHandle((RuntimeMethodHandle)obj, default));
return importer.ImportAsOperand(SR.MethodBase.GetMethodFromHandle((RuntimeMethodHandle)obj, default));
}
else
return importer.Import(SR.MethodBase.GetMethodFromHandle((RuntimeMethodHandle)obj));
return importer.ImportAsOperand(SR.MethodBase.GetMethodFromHandle((RuntimeMethodHandle)obj));
}

if (obj.GetType().ToString() == "System.Reflection.Emit.GenericMethodInfo") {
var context = (RuntimeTypeHandle)gmiContextFieldInfo.Read(obj);
var method = SR.MethodBase.GetMethodFromHandle((RuntimeMethodHandle)gmiMethodHandleFieldInfo.Read(obj), context);
return importer.Import(method);
return importer.ImportAsOperand(method);
}

if (obj.GetType().ToString() == "System.Reflection.Emit.VarArgMethod") {
var method = GetVarArgMethod(obj);
if (!(method is DynamicMethod))
return importer.Import(method);
return importer.ImportAsOperand(method);
obj = method;
}

Expand Down Expand Up @@ -506,25 +506,28 @@ IField ImportField(uint rid) {
if ((options & DynamicMethodBodyReaderOptions.UnknownDeclaringType) != 0) {
// Sometimes it's a generic type but obj != `GenericFieldInfo`, so pass in 'default' and the
// runtime will try to figure out the declaring type. https://github.com/0xd4d/dnlib/issues/298
return importer.Import(SR.FieldInfo.GetFieldFromHandle((RuntimeFieldHandle)obj, default));
return importer.ImportAsOperand(SR.FieldInfo.GetFieldFromHandle((RuntimeFieldHandle)obj, default));
}
else
return importer.Import(SR.FieldInfo.GetFieldFromHandle((RuntimeFieldHandle)obj));
return importer.ImportAsOperand(SR.FieldInfo.GetFieldFromHandle((RuntimeFieldHandle)obj));
}

if (obj.GetType().ToString() == "System.Reflection.Emit.GenericFieldInfo") {
var context = (RuntimeTypeHandle)gfiContextFieldInfo.Read(obj);
var field = SR.FieldInfo.GetFieldFromHandle((RuntimeFieldHandle)gfiFieldHandleFieldInfo.Read(obj), context);
return importer.Import(field);
return importer.ImportAsOperand(field);
}

return null;
}

ITypeDefOrRef ImportType(uint rid) {
ITypeDefOrRef ImportType(uint rid, bool ldtoken) {
var obj = Resolve(rid);
if (obj is RuntimeTypeHandle)
return importer.Import(Type.GetTypeFromHandle((RuntimeTypeHandle)obj));
if (obj is RuntimeTypeHandle) {
if (ldtoken)
return importer.Import(Type.GetTypeFromHandle((RuntimeTypeHandle)obj));
return importer.ImportAsOperand(Type.GetTypeFromHandle((RuntimeTypeHandle)obj));
}

return null;
}
Expand Down
64 changes: 43 additions & 21 deletions src/DotNet/Importer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using dnlib.DotNet.Emit;

namespace dnlib.DotNet {
/// <summary>
Expand Down Expand Up @@ -167,22 +168,22 @@ public Importer(ModuleDef module, ImporterOptions options, GenericParamContext g
}

/// <summary>
/// Imports a <see cref="Type"/> as a <see cref="ITypeDefOrRef"/>.
/// Imports a <see cref="Type"/> as an <see cref="ITypeDefOrRef"/>.
/// </summary>
/// <param name="type">The type</param>
/// <returns>The imported type or <c>null</c> if <paramref name="type"/> is invalid</returns>
public ITypeDefOrRef Import(Type type) => module.UpdateRowId(ImportAsTypeSig(type).ToTypeDefOrRef());

/// <summary>
/// Imports a <see cref="Type"/> as a <see cref="ITypeDefOrRef"/>. See also <see cref="Import(Type)"/>
/// Imports a <see cref="Type"/> as an <see cref="ITypeDefOrRef"/>. See also <see cref="Import(Type)"/>
/// </summary>
/// <param name="type">The type</param>
/// <returns></returns>
[Obsolete("Use 'Import(Type)' instead.")]
public ITypeDefOrRef ImportDeclaringType(Type type) => Import(type);

/// <summary>
/// Imports a <see cref="Type"/> as a <see cref="ITypeDefOrRef"/>
/// Imports a <see cref="Type"/> as an <see cref="ITypeDefOrRef"/>
/// </summary>
/// <param name="type">The type</param>
/// <param name="requiredModifiers">A list of all required modifiers or <c>null</c></param>
Expand Down Expand Up @@ -399,7 +400,7 @@ IResolutionScope CreateScopeReference(Type type) {
}

/// <summary>
/// Imports a <see cref="Type"/> as a <see cref="ITypeDefOrRef"/>
/// Imports a <see cref="Type"/> as an <see cref="ITypeDefOrRef"/>
/// </summary>
/// <param name="type">The type</param>
/// <param name="requiredModifiers">A list of all required modifiers or <c>null</c></param>
Expand Down Expand Up @@ -437,17 +438,15 @@ TypeSig ImportAsTypeSig(Type type, IList<Type> requiredModifiers, IList<Type> op
static bool IsEmpty<T>(IList<T> list) => list is null || list.Count == 0;

/// <summary>
/// Imports a <see cref="MethodBase"/> as a <see cref="IMethod"/>. This will be either
/// a <see cref="MemberRef"/> or a <see cref="MethodSpec"/>.
/// Imports a <see cref="MethodBase"/> as an <see cref="IMethod"/>.
/// </summary>
/// <param name="methodBase">The method</param>
/// <returns>The imported method or <c>null</c> if <paramref name="methodBase"/> is invalid
/// or if we failed to import the method</returns>
public IMethod Import(MethodBase methodBase) => Import(methodBase, false);

/// <summary>
/// Imports a <see cref="MethodBase"/> as a <see cref="IMethod"/>. This will be either
/// a <see cref="MemberRef"/> or a <see cref="MethodSpec"/>.
/// Imports a <see cref="MethodBase"/> as an <see cref="IMethod"/>.
/// </summary>
/// <param name="methodBase">The method</param>
/// <param name="forceFixSignature">Always verify method signature to make sure the
Expand All @@ -459,9 +458,7 @@ public IMethod Import(MethodBase methodBase, bool forceFixSignature) {
return ImportInternal(methodBase, forceFixSignature);
}

IMethod ImportInternal(MethodBase methodBase) => ImportInternal(methodBase, false);

IMethod ImportInternal(MethodBase methodBase, bool forceFixSignature) {
IMethod ImportInternal(MethodBase methodBase, bool forceFixSignature, bool asOperand = false) {
if (methodBase is null)
return null;

Expand All @@ -484,13 +481,13 @@ IMethod ImportInternal(MethodBase methodBase, bool forceFixSignature) {
if (methodBase.DeclaringType.GetElementType2() == ElementType.GenericInst)
method = module.UpdateRowId(new MemberRefUser(module, methodBase.Name, CreateMethodSig(origMethod), Import(methodBase.DeclaringType)));
else
method = ImportInternal(origMethod) as IMethodDefOrRef;
method = ImportInternal(origMethod, forceFixSignature, asOperand) as IMethodDefOrRef;

method = TryResolveMethod(method);
if (methodBase.ContainsGenericParameters)
if (!asOperand && methodBase.ContainsGenericParameters)
return method; // Declaring type is instantiated but method itself is not

var gim = CreateGenericInstMethodSig(methodBase);
var gim = CreateGenericInstMethodSig(methodBase, asOperand);
var methodSpec = module.UpdateRowId(new MethodSpecUser(method, gim));
if (FixSignature && !forceFixSignature) {
//TODO:
Expand All @@ -504,7 +501,7 @@ IMethod ImportInternal(MethodBase methodBase, bool forceFixSignature) {
parent = GetModuleParent(methodBase.Module);
}
else
parent = Import(methodBase.DeclaringType);
parent = asOperand ? ImportAsOperand(methodBase.DeclaringType) : Import(methodBase.DeclaringType);
if (parent is null)
return null;

Expand Down Expand Up @@ -583,11 +580,11 @@ CallingConvention GetCallingConvention(MethodBase mb) {
return cc;
}

GenericInstMethodSig CreateGenericInstMethodSig(MethodBase mb) {
GenericInstMethodSig CreateGenericInstMethodSig(MethodBase mb, bool asOperand) {
var genMethodArgs = mb.GetGenericArguments();
var gim = new GenericInstMethodSig(CallingConvention.GenericInst, (uint)genMethodArgs.Length);
foreach (var gma in genMethodArgs)
gim.GenericArguments.Add(ImportAsTypeSig(gma));
gim.GenericArguments.Add(asOperand ? ImportAsTypeSig(gma, null, gma.IsGenericType) : ImportAsTypeSig(gma));
return gim;
}

Expand All @@ -604,22 +601,24 @@ bool IsThisAssembly(Module module2) {
}

/// <summary>
/// Imports a <see cref="FieldInfo"/> as a <see cref="MemberRef"/>
/// Imports a <see cref="FieldInfo"/> as an <see cref="IField"/>
/// </summary>
/// <param name="fieldInfo">The field</param>
/// <returns>The imported field or <c>null</c> if <paramref name="fieldInfo"/> is invalid
/// or if we failed to import the field</returns>
public IField Import(FieldInfo fieldInfo) => Import(fieldInfo, false);

/// <summary>
/// Imports a <see cref="FieldInfo"/> as a <see cref="MemberRef"/>
/// Imports a <see cref="FieldInfo"/> as an <see cref="IField"/>
/// </summary>
/// <param name="fieldInfo">The field</param>
/// <param name="forceFixSignature">Always verify field signature to make sure the
/// returned reference matches the metadata in the source assembly</param>
/// <returns>The imported field or <c>null</c> if <paramref name="fieldInfo"/> is invalid
/// or if we failed to import the field</returns>
public IField Import(FieldInfo fieldInfo, bool forceFixSignature) {
public IField Import(FieldInfo fieldInfo, bool forceFixSignature) => ImportInternal(fieldInfo, forceFixSignature, false);

IField ImportInternal(FieldInfo fieldInfo, bool forceFixSignature, bool asOperand = false) {
FixSignature = false;
if (fieldInfo is null)
return null;
Expand All @@ -642,7 +641,7 @@ public IField Import(FieldInfo fieldInfo, bool forceFixSignature) {
parent = GetModuleParent(fieldInfo.Module);
}
else
parent = Import(fieldInfo.DeclaringType);
parent = asOperand ? ImportAsOperand(fieldInfo.DeclaringType) : Import(fieldInfo.DeclaringType);
if (parent is null)
return null;

Expand Down Expand Up @@ -1190,5 +1189,28 @@ IMemberRefParent Import(IMemberRefParent parent) {

return null;
}

/// <summary>
/// Imports a <see cref="Type"/> as an <see cref="ITypeDefOrRef"/> used for <see cref="Instruction.Operand"/>.
/// </summary>
/// <param name="type">The type</param>
/// <returns>The imported type or <c>null</c> if <paramref name="type"/> is invalid</returns>
public ITypeDefOrRef ImportAsOperand(Type type) => module.UpdateRowId(ImportAsTypeSig(type, null, type.IsGenericType).ToTypeDefOrRef());

/// <summary>
/// Imports a <see cref="MethodBase"/> as an <see cref="IMethod"/> used for <see cref="Instruction.Operand"/>.
/// </summary>
/// <param name="methodBase">The method</param>
/// <returns>The imported method or <c>null</c> if <paramref name="methodBase"/> is invalid
/// or if we failed to import the method</returns>
public IMethod ImportAsOperand(MethodBase methodBase) => ImportInternal(methodBase, false, true);

/// <summary>
/// Imports a <see cref="FieldInfo"/> as an <see cref="IField"/> used for <see cref="Instruction.Operand"/>.
/// </summary>
/// <param name="fieldInfo">The field</param>
/// <returns>The imported field or <c>null</c> if <paramref name="fieldInfo"/> is invalid
/// or if we failed to import the field</returns>
public IField ImportAsOperand(FieldInfo fieldInfo) => ImportInternal(fieldInfo, false, true);
}
}
Loading