2017-10-25 1 views
5

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?

wird
.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 ...

+1

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

+2

Leider kann ich das nicht reproduzieren. Ist 'ldarg.0' zum' call' notwendig? – IllidanS4

+2

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. –

Antwort

2

Leider scheint es, ich CLR Fehler ...

Hit

Alles funktioniert wenn das Vermächtnis JIT-Compiler:

set COMPLUS_useLegacyJit=1

war ich nicht in der Lage eine bestimmte RyuJit Einstellung zu isolieren, die dieses verursachen kann. Ich folgte der Empfehlung in diesem Artikel:
https://github.com/Microsoft/dotnet/blob/master/Documentation/testing-with-ryujit.md

Vielen Dank an alle, die geholfen haben!

+2

Vielleicht möchten Sie ein Problem für das CoreCLR-Repository (das RyuJIT enthält); Es gibt bereits [mehrere] (https://github.com/dotnet/coreclr/search?type=Issues) für "localloc".'localloc' ist in' finally' nicht erlaubt, daher ist es möglich, dass der Jitter verwirrt wird und es hier nicht erlaubt, obwohl er nicht im Block ist. –

+0

@JeroenMostert danke! Ich vermutete, dass dies der Fall sein könnte ... Ich laufe auf .NET 4.6, also werde ich prüfen, ob dies auf der neuesten CoreCLR reproduziert. Ich bemerkte einen ähnlichen Fehler, der bereits behoben wurde, also sind die Chancen, dass dies bereits behoben sein kann: https://github.com/dotnet/coreclr/blob/master/tests/src/JIT/Regression/VS- ia64-JIT/V1.2-M01/b10841/repro_good.il – valiano

+0

Schöner Fang! Ich frage mich, was die Ursache für den Fehler ist. – IllidanS4

Verwandte Themen