私は次の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私がデバッグだプログラムが...悲しいこと
コンパイル済みDLLをILSpyで開くと、表示されるコードが表示されますか? (おそらくILのビューでのみ - これはおそらくC#に逆コンパイルされませんが、私は間違っているかもしれません) – xxbbcc
悲しいことに、私はこれを再現することはできません。 'ldarg.0'は' call'する必要がありますか? – IllidanS4
peverify.exeがどのように使用されるかははっきりしていませんが、locallocが好きではありません。そのldarg.0はスタックの不均衡なので、List <>のデフォルトコンストラクタを呼び出しています。ただそれを削除します。 –