2

匿名でホストされている動的メソッドを使用しているときに、パブリッククラスのパブリック仮想メソッドに対してldvirtftnによって検証できない例外が発生する理由を誰かが説明できますか?次のアセンブリレベル属性も設定しました。

[assembly: SecurityTransparent]
[assembly: SecurityRules(SecurityRuleSet.Level2,SkipVerificationInFullTrust=true)]

サンプルコードは次のとおりです。

public class Program
{
    public virtual void Foo() {}
    public static void Main(string[] args)
    {
        Action<ILGenerator> genfunc = il => il
            .newobj<Program>()
            .ldvirtftn(typeof(Program).GetMethod("Foo"))
            .ret();
        try
        {
            Console.WriteLine(CodeGen.CreateDelegate<Func<IntPtr>>(genfunc).Invoke());

        }
        catch (System.Security.VerificationException) { }
        Console.WriteLine(CodeGen.CreateDelegate<Func<IntPtr>>(genfunc,owner:typeof(Program)).Invoke());
    }
}

メソッドが所有されている場合、例外はスローされません。

さらに興味深いのは、このようにコードを変更すると、両方のメソッドが問題なくコンパイルおよび実行されることです。

public class Program
{
    public virtual void Foo() {}
    public static void Main(string[] args)
    {
        Action<ILGenerator> genfunc = il => il
            .newobj<Program>()
            .dup()
            .ldvirtftn(typeof(Program).GetMethod("Foo"))
            .newobj<Action>(typeof(object),typeof(IntPtr))
            .ret();
        try
        {
            Console.WriteLine(CodeGen.CreateDelegate<Func<Action>>(genfunc).Invoke());
        }
        catch (System.Security.VerificationException) { }
        Console.WriteLine(CodeGen.CreateDelegate<Func<Action>>(genfunc,owner:typeof(Program)).Invoke());
    }
}

このコードはリフレクティブライブラリで書かれています。

CodeGen.CreateDelegateは、typeパラメーターを使用して、動的メソッドのシグニチャーを判別するだけです。方法は次のとおりです。

    public static TDelegate CreateDelegate<TDelegate>(
        Action<ILGenerator> genfunc, string name = "", object target = null, Type owner = null, bool skipVisibility = false)
        where TDelegate : class
    {
        var invokeMethod = typeof(TDelegate).GetMethod("Invoke");
        var parameters = invokeMethod.GetParameters();
        var paramTypes = new Type[parameters.Length + 1];
        paramTypes[0] = typeof(object);
        parameters.Select(p => p.ParameterType).ToArray().CopyTo(paramTypes, 1);
        var method = owner != null ?
            new DynamicMethod(name, invokeMethod.ReturnType, paramTypes, owner, skipVisibility) :
            new DynamicMethod(name, invokeMethod.ReturnType, paramTypes, skipVisibility);
        genfunc(method.GetILGenerator());
        return method.CreateDelegate(typeof(TDelegate), target) as TDelegate;
    }
4

3 に答える 3

4

短い答え

送信しようとしているコードは検証不可能であり、匿名でホストされている動的メソッドに検証不可能なILを含めることはできません。タイプまたはモジュールに関連付けられた動的メソッドには検証不可能なILが含まれている可能性があるため(適切なセキュリティチェックの対象)、コードはそれらの動的メソッドから使​​用できます。

モードの詳細

MSDNのドキュメントにも関わらず、ldvirtftnはネイティブintをスタックにロードしません。メソッドポインタをロードします。オブジェクト参照をネイティブintとして扱うことは有効ですが検証できないのと同様に、メソッドポインタをネイティブintとして扱うことも有効ですが、検証できません。これを確認する最も簡単な方法は、同じIL命令を使用してディスク上にアセンブリを作成し(たとえば、System.Reflection.Emitまたはilasmを使用して)、その上でPEVerifyを実行することです。

メソッドポインタの検証可能な使用法は次のとおりです。

  • dup; ldvirtftn; newobjまたはパターンを使用してデリゲートを構築しldftn; newobj、互換性のあるデリゲートタイプの新しいデリゲートを作成します
  • calli互換性のある引数を使用して、メソッドポインタを介して間接呼び出しを行う

これは、匿名でホストされる動的メソッドを介して他のコードを呼び出すことができる理由を説明しています。使用しているデリゲート作成パターンは、メソッドポインターの数少ない検証可能な使用法の1つです。

于 2012-04-02T21:16:26.050 に答える
0

奇妙な動作 (IntPtr != IntPtr):

//work normal
public static void F_Ldvirtftn_Action()
{
  Action<ILGenerator> genfunc = il =>
  {
    il.Emit(OpCodes.Newobj, typeof(Program).GetConstructor(Type.EmptyTypes));
    il.Emit(OpCodes.Dup);
    il.Emit(OpCodes.Ldvirtftn, typeof(Program).GetMethod("Foo2"));
    il.Emit(OpCodes.Newobj, typeof(Action).GetConstructor(new[] { typeof(object), typeof(IntPtr) }));
    il.Emit(OpCodes.Ret);
  };
  Console.WriteLine(CreateDelegate<Func<object>>(genfunc).Invoke());
}
// failed: VerificationException: Operation could destabilize the runtime
public static void F_IntPtr_Action()
{
  Action<ILGenerator> genfunc = il =>
  {
    il.Emit(OpCodes.Newobj, typeof(Program).GetConstructor(Type.EmptyTypes));
    il.Emit(OpCodes.Dup);
    il.Emit(OpCodes.Call, typeof(Program).GetMethod("Ptr"));
    il.Emit(OpCodes.Newobj, typeof(Action).GetConstructor(new[] { typeof(object), typeof(IntPtr) }));
    il.Emit(OpCodes.Ret);
  };
  Console.WriteLine(CreateDelegate<Func<object>>(genfunc).Invoke());
}
// failed: VerificationException: Operation could destabilize the runtime 
public static void F_Ldvirtftn_MyAction()
{
  Action<ILGenerator> genfunc = il =>
  {
    il.Emit(OpCodes.Newobj, typeof(Program).GetConstructor(Type.EmptyTypes));
    il.Emit(OpCodes.Dup);
    il.Emit(OpCodes.Ldvirtftn, typeof(Program).GetMethod("Foo2"));
    il.Emit(OpCodes.Newobj, typeof(MyAction).GetConstructor(new[] { typeof(object), typeof(IntPtr) }));
    il.Emit(OpCodes.Ret);
  };
  Console.WriteLine(CreateDelegate<Func<object>>(genfunc).Invoke());
}
//work normal
public static void F_IntPtr_MyAction()
{
  Action<ILGenerator> genfunc = il =>
  {
    il.Emit(OpCodes.Newobj, typeof(Program).GetConstructor(Type.EmptyTypes));
    il.Emit(OpCodes.Dup);
    il.Emit(OpCodes.Call, typeof(Program).GetMethod("Ptr"));
    il.Emit(OpCodes.Newobj, typeof(MyAction).GetConstructor(new[] { typeof(object), typeof(IntPtr) }));
    il.Emit(OpCodes.Ret);
  };
  Console.WriteLine(CreateDelegate<Func<object>>(genfunc).Invoke());
}

public static IntPtr Ptr(object z)
{
  return IntPtr.Zero;
}
public class MyAction
{
  public MyAction(object z, IntPtr adr) { }
}
于 2012-04-01T01:43:59.160 に答える
0

ldvirtfn はネイティブの int をスタックにロードします。戻る前に、まずそれを IntPtr に変換する必要があると思います。

于 2012-03-31T20:48:26.733 に答える