Ich habe das folgende Stück reduzierten CIL-Code.
Wenn diese CIL-Methode ausgeführt wird, wird ein InvalidProgramException wird von der CLR geworfen:Warum bricht localloc diese CIL-Methode?
.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
Meine Frage, warum ist der CIL-Code ungültig?
Mehrere Überarbeitungen:
- Wenn localloc
entfernt wird, läuft der Code gut. Nach meinem Wissen ersetzt localloc
die Parametergröße auf dem Stapel durch eine Adresse, so dass der Stapel ausgeglichen bleibt, AFAICT.
- Wenn die Blöcke try und finally entfernt werden, läuft der Code einwandfrei.
- Wenn der erste Block mit Anweisungen, der localloc
enthält, nach dem try-finally-Block verschoben wird, wird der Code ordnungsgemäß ausgeführt.
Es scheint also etwas in der Kombination von Localloc und dem Versuch - endlich.
Einige Hintergrundinformationen:
I nach dem InvalidProgramException zu diesem Punkt bekam, war für die ursprüngliche Methode ausgelöst, aufgrund einiger in Runtime gemacht Instrumentierung. Mein Ansatz dies für das Debuggen, um herauszufinden, was falsch ist mit der Instrumentierung ist:
- Auseinanderbauen den fehlerhaften DLL mit
ildasm
- Anwendung des Instrumentationscode auf das Krachen Methode
- Recreating die DLL aus dem modifizierten IL mit
ilasm
- das Programm erneut ausgeführt wird, und die Überprüfung stürzt
- Halten sie den IL-Code des Krachen Verfahren reduziert gradualy, bis auf die minimale Szenario, das das Problem verursacht (und versuchen, nicht in int roduce Bugs auf dem Weg ...)
Leider zeigte peverify.exe /IL
keinen Fehler. Ich habe versucht, die ECMA-Spezifikation und Serge Lidins Expert .NET IL Buch zu trösten, konnte aber nicht herausfinden, was falsch läuft.
Gibt es etwas Grundlegendes, das ich vermisse?
Edit:
ich leicht den IL-Code in Frage aktualisiert, um es komplett (ohne Anweisungen zu ändern). Der zweite Anweisungsblock, einschließlich ldarg
, newobj
usw., wird aus dem Arbeitscode übernommen - dem ursprünglichen Methodencode.
Was ist komisch für mich, entweder durch localloc
oder .try
Entfernen - finally
, der Code funktioniert - aber keiner von ihnen, meines Wissens, sollte den Ausgleich des Stapels zu ändern, im Vergleich zu, wenn sie im Code vorhanden sind .
Hier ist der IL-Code mit ILSpy in C# dekompilierten:
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
{
}
}
Edit 2:
Weitere Beobachtungen:
- Unter dem localloc
Block von IL-Code, und es bis zum Ende zu bewegen der Code läuft gut - so scheint es, dass Code für sich in Ordnung ist.
- Das Problem wird nicht reproduziert, wenn ähnlicher IL-Code in eine Hallo-Welt-Testfunktion eingefügt wird.
ich sehr verwirrt bin ...
Ich wünsche es eine Möglichkeit, mehr Informationen aus der InvalidProgramException bekommen sollte. Es scheint, dass die CLR nicht den genauen Fehlergrund an das Ausnahmeobjekt anfügt. Ich dachte auch auf das Debuggen mit CoreCLR Debug-Build, aber sich leider das Programm, das ich Debuggen bin ist damit nicht kompatibel ...
Wenn Sie Ihre kompilierte DLL in ILSpy öffnen, wird der Code angezeigt, den Sie erwarten? (Wahrscheinlich nur in der IL-Ansicht - das wird wahrscheinlich nicht in C# dekompiliert, obwohl ich falsch liegen kann.) – xxbbcc
Leider kann ich das nicht reproduzieren. Ist 'ldarg.0' zum' call' notwendig? – IllidanS4
Ziemlich unklar, wie peverify.exe verwendet werden könnte, mag es nicht localloc. Wenn ldarg.0 den Stack aus dem Gleichgewicht bringt, rufen Sie den Standardkonstruktor von List <> auf. Löschen Sie es einfach. –