2012-03-31 12 views
2

パブリッククラスのパブリック仮想メソッドのldvirtftnによって、匿名でホストされた動的メソッドを使用すると誰が説明できないのですか?私は、次のアセンブリレベルが同様に属性を設定します。ここでは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; 
    } 
+0

MSILはマネージコードだけではありません。生のネイティブC++コードをILにコンパイルすることもできます。 C++/CLIコンパイラが完了しました。 Opcodes.Ldvirtfnが重要なコードの種類は、v-tableから関数ポインタを掘り下げます。ジッタ・ベリファイアがそれに当たったときに、生のアドレスIntPtrは検証のヘッケーフロールではありません。 –

+0

真実ですが、なぜメソッドを所有する型にすると検証の問題はなくなりますか? –

答えて

4

短い答え

コードは検証不可能で、かつ匿名で動的メソッドを開催しましたが、検証不可能ILを含めることはできません。型またはモジュールに関連付けられた動的メソッドには、検証不能なIL(適切なセキュリティチェックの対象)が含まれている可能性があるため、これらの動的メソッドからコードを使用できます。 MSDNのドキュメントにもかかわらず

モードの詳細

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

私はメソッドポインタの唯一の検証用途があると考えてい

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

これは、他のコードを匿名でホストされたダイナミックメソd:使用しているデリゲートの作成パターンは、メソッドポインタの検証可能な使用法のうちの1つです。

+0

PEVerifyは、カルスは常に正当なものであると考えています(意味があります)。 http://blogs.msdn.com/b/shawnfa/archive/2004/06/14/155478.aspx 非常に奇妙ですが、完全に信じられます。 –

+0

@MichaelB - 良い点、私はECMA仕様がカバーするルールを列挙しました。これはPEVerifyが実際に実装するものと同じではありません。 – kvb

0

ldvirtfnはネイティブintをスタックにロードします。私はそれをIntPtrに変換してから返す必要があると思います。

+0

conv_iまたはconv_uを呼び出しても、この子犬は実行可能になりません。あなたはそれが返品の問題であるかもしれないかもしれません。検証問題は、uintを返す関数が実際のintを返し、最初に変換しない場合にも表示されます。 (例:ldc_m1 ret) –

+0

'IntPtr's *は* native intです。 – kvb

+0

緊急対策として、conv.i8を使用してIntPtr(long)オーバーロードを使用することができます。 – usr

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) { } 
} 
関連する問題