2017-10-25 22 views
5

私は次のCILコードを減らしました。
このCILメソッドが実行されると、InvalidProgramExceptionは、CLRによってスローされているが:なぜlocallocはこのCILメソッドを中断しますか?

.method assembly hidebysig specialname rtspecialname 
      instance void .ctor(class [mscorlib]System.Collections.Generic.IEnumerable`1<class System.Windows.Input.StylusDeviceBase> styluses) cil managed 
    { 
    .locals init (class [mscorlib]System.Collections.Generic.IEnumerator`1<class System.Windows.Input.StylusDeviceBase> V_0, 
     class System.Windows.Input.StylusDeviceBase V_1) 

    ldc.i4.8 // These instructions cause CIL to break 
    conv.u  // 
    localloc // 
    pop  // 

    ldarg.0 
    newobj instance void class [mscorlib]System.Collections.Generic.List`1<class System.Windows.Input.StylusDevice>::.ctor() 
    call instance void class [mscorlib]System.Collections.ObjectModel.ReadOnlyCollection`1<class System.Windows.Input.StylusDevice>::.ctor(class [mscorlib]System.Collections.Generic.IList`1<!0>) 
    ldarg.1 
    callvirt instance class [mscorlib]System.Collections.Generic.IEnumerator`1<!0> class [mscorlib]System.Collections.Generic.IEnumerable`1<class System.Windows.Input.StylusDeviceBase>::GetEnumerator() 
    stloc.0 

    .try 
    { 
     leave.s IL_0040 
    } 
    finally 
    { 
     endfinally 
    } 

    IL_0040: ret 
    } // end of method StylusDeviceCollection::.ctor 

私の質問は、なぜこのCILコードは無効ですか?

複数の恩恵:​​
- locallocが削除された場合、コードは正常に動作します。私の知る限り、locallocはスタック上のパラメータサイズをアドレスに置き換えているので、スタックはAFAICTのままです。
- tryブロックとfinallyブロックが削除された場合、コードは正常に動作します。
- locallocを含む命令の最初のブロックがtry-finallyブロックの後に移動されると、コードは正常に実行されます。

これはlocallocとtry-finallyの組み合わせの中で何かのようです。

いくつかの背景:

InvalidProgramExceptionは実行時に作られたいくつかの計測のためにオリジナルの方法、のためにスローされた後、私は、この点になりました。これをデバッグするための私のアプローチは、計装と間違っているかを把握するために、次のとおりです。

  • が修正からDLLを再作成クラッシュ方法
  • に計測コードを適用ildasm
  • に障害のあるDLLを分解しますILはilasm
  • が再びプログラムを実行し、検証することでそれが
  • キープ問題が発生する最小限のシナリオに至るまで、gradualyクラッシュメソッドのILコードを減らす(とintにないようにしようとクラッシュ道に沿ってバグを誘発する...)

残念ながら、peverify.exe /ILはエラーを示さなかった。 私はECMA仕様とSerge Lidinのエキスパート.NET ILの本をコンソールにしようとしましたが、何が問題になるのか理解できませんでした。

何か基本的なものがありますか?

編集:私は少し(指示を変更することなく)、それはより完全にするために、問題のILコードを更新

ldarg,newobjなどの2番目の命令ブロックは、元のメソッドコードであるワーキングコードからそのまま使用されます。

何私には奇妙なで、どちらかlocallocまたは.try除去することで - finally、コードが動作する - しかし、これらのどれもが、私の知る限り、彼らはコード内に存在している場合に比べて、スタックのバランスを変更する必要があります。ここ

がILSpy有するC位に逆コンパイルILコードは次のとおり

internal unsafe StylusDeviceCollection(IEnumerable<StylusDeviceBase> styluses) 
{ 
    IntPtr arg_04_0 = stackalloc byte[(UIntPtr)8]; 
    base..ctor(new List<StylusDevice>()); 
    IEnumerator<StylusDeviceBase> enumerator = styluses.GetEnumerator(); 
    try 
    { 
    } 
    finally 
    { 
    } 
} 

編集2:

詳細観察:
- ILコードのlocallocブロックを取って、そして最後にそれを移動させますコードはうまく動作するので、コード自体は問題ありません。
- 同様のILコードをhello worldテスト関数に貼り付ける際に問題が再現されません。私は非常に困惑してい

...

は私がInvalidProgramExceptionからのより多くの情報を取得する方法があったことを望みます。 CLRは、例外オブジェクトに正確な失敗理由を添付していないようです。 私もCoreCLRのデバッグビルドとデバッグに思ったが、unforunately私がデバッグだプログラムが...悲しいこと

+1

コンパイル済みDLLをILSpyで開くと、表示されるコードが表示されますか? (おそらくILのビューでのみ - これはおそらくC#に逆コンパイルされませんが、私は間違っているかもしれません) – xxbbcc

+2

悲しいことに、私はこれを再現することはできません。 'ldarg.0'は' call'する必要がありますか? – IllidanS4

+2

peverify.exeがどのように使用されるかははっきりしていませんが、locallocが好きではありません。そのldarg.0はスタックの不均衡なので、List <>のデフォルトコンストラクタを呼び出しています。ただそれを削除します。 –

答えて

2

それとは互換性がありません、

すべてが働いている...私はCLRのバグを打つようです従来のJITコンパイラを使用する場合:

set COMPLUS_useLegacyJit=1

私はこれを引き起こすことができる特定RyuJit設定を単離することができませんでした。 私はこの記事の推奨に従った:
https://github.com/Microsoft/dotnet/blob/master/Documentation/testing-with-ryujit.md

助けてくれた皆様に感謝します!

+2

あなたは問題を開くことができます。 CoreCLRリポジトリ(RyuJITを含む)。 'localloc'には既にいくつか(https://github.com/dotnet/coreclr/search?type=Issues)あります。'localloc'は' finally'には許可されていないので、ジッターが混乱し、ブロック内にないのに完全にここでそれを許さない可能性があります。 –

+0

@ JeroenMostertありがとう!私はこれが事実かもしれないと思っています... 私は.NET 4.6で動作していますので、これが最新のCoreCLRで再現するかどうかを確認します。 すでに修正されている同様のバグに気づいたので、チャンスは既に修正されている可能性があります。 https://github.com/dotnet/coreclr/blob/master/tests/src/JIT/Regression/VS- ia64-JIT/V1.2-M01/b10841/repro_good.il – valiano

+0

ニースキャッチ!バグの原因が何であるのだろうか。 – IllidanS4

関連する問題