2016-08-02 24 views
0

Ich habe ein Httphandler, die wie folgt aussieht:C# Httphandler stürzt IIS - aber nur in Release-Modus mit Optimierungen auf

public class GoodIISHandler : IHttpHandler 
{ 
    public void ProcessRequest(HttpContext context) 
    { 
     try 
     { 
      try 
      { 
       context.Response.End(); 
      } 
      catch (Exception) 
      { 
      } 
     } 
     finally 
     { 
      Console.WriteLine("Inside finally block"); 
     } 
    } 

    public bool IsReusable => true; 
} 

Es funktioniert gut! Außer im Kompilierungsmodus mit optimierten Optimierungen, die anschließend ausgeführt werden (auf Windows Server 2012, auf dem IIS 8 mit .NET 4.5.2 ausgeführt wird). Dann stürzt es IIS ab.

Eine nicht behandelte Ausnahme ist aufgetreten und der Prozess wurde beendet.

Anwendungs-ID:/LM/W3SVC/1592535739/ROOT/HttpHandlerApp

Prozess-ID: 648

Ausnahme: System.Threading.ThreadAbortException

Nachricht: Thread wurde abgebrochen.

Stacktrace: bei System.Web.HttpRuntime.ProcessRequestNotificationPrivate (IIS7WorkerRequest wr, Httpcontext context)

bei System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper (IntPtr rootedObjectsPointer, IntPtr nativeRequestContext, IntPtr moduleData, Int32 flags)

bei System.Web.Hosting.PipelineRuntime.ProcessRequestNotification (IntPtr rootedObjectsPointer, IntPtr nativeRequestContext, IntPtr moduleData, Fahnen Int32)

und

Fehlgeschlagene Anwendung Name: w3wp.exe, Version: 8.0.9200.16384, Zeitstempel: 0x50108835

Fehlgeschlagene Modulname: KERNELBASE.dll, Version: 6.2.9200.17366, Zeitstempel: 0x554d4531

Ausnahmecode: 0xe0434352

Fehler Offset: 0x000000000004aea8

Fehlgeschlagene Prozess-ID: 0x288

Fehlgeschlagene Anwendung Startzeit: 0x01d1ec2c7db735a6

Auftragweg Fehlgeschlagene: c: \ windows \ system32 \ inetsrv \ w3wp.exe

Fehlgeschlagene Modulpfad: C: \ WINDOWS \ system32 \ KERNELBASE.dll

Report Id: bb7471fa-581f-11e6-93f1-00155d461b1c

Fehlgeschlagene Paket voller Name:

Fehlgeschlagene Paket-Relativ Anwendungs-ID:

Ich habe das Problem auf ein bestimmtes Bit der IL eingeschränkt, das sich ändert, wenn die Optimierung aktiviert/deaktiviert ist.Hier

ist die IL für ProcessRequest, die nicht IIS nicht abstürzen:

.method public hidebysig newslot virtual final 
     instance void ProcessRequest(class [System.Web]System.Web.HttpContext context) cil managed 
{ 
    // Code size  30 (0x1e) 
    .maxstack 1 
    .try 
    { 
    .try 
    { 
     IL_0000: ldarg.1 
     IL_0001: callvirt instance class [System.Web]System.Web.HttpResponse [System.Web]System.Web.HttpContext::get_Response() 
     IL_0006: callvirt instance void [System.Web]System.Web.HttpResponse::End() 
     IL_000b: leave.s IL_0010 

    } // end .try 
    catch [mscorlib]System.Exception 
    { 
     IL_000d: pop 
     IL_000e: leave.s IL_0010 

    } // end handler 
    IL_0010: leave.s IL_001d 

    } // end .try 
    finally 
    { 
    IL_0012: ldstr  "Inside finally block" 
    IL_0017: call  void [mscorlib]System.Console::WriteLine(string) 
    IL_001c: endfinally 
    } // end handler 
    IL_001d: ret 
} // end of method GoodIISHandler::ProcessRequest 

Um IIS zum Absturz zu bringen, ändern Linie 19 bis

 IL_000e: leave.s IL_001d 

Diese Änderung Ausgang des verschachtelten catch-Block macht direkt an die Methodenrückgabeanweisung, ohne die einzelne Anweisung zu besuchen, die im try-Block des try..finally bleibt.

Meine Hypothese ist, dass der Absturz bezieht sich auf die magische Auto-Retrow-Verhalten von ThreadAbortException (von denen context.Response.End() wird werfen) und wie die CLR und/oder IIS und/oder ASP.NET das verwaltet; Wenn also die optimierte IL vom catch-Block direkt zur Rückgabeanweisung übergeht, wird eine hypothetische Abbruch-Reset-Magie, die CLR/IIS/ASP.NET bei IL_0010 eingefügt hat, verpasst und die ThreadAbortException nimmt den gesamten IIS herunter.

Es gibt Hinweise, um das Internet zu diesem Verhalten verstreut (z these msdn docs Zustand ThreadAbortException is a special exception that can be caught, but it will automatically be raised again at the end of the catch block. und this blog erwähnt ... notably ASP.NET, even aborts individual threads routinely without unloading the domain. They backstop the ThreadAbortExceptions, call ResetAbort on the thread and reuse it or return it to the CLR ThreadPool.), aber ich kann nichts Konkretes über den Mechanismus finden.

Also ich denke, meine Frage ist: Was ist hier los? Habe ich wirklich einen CLR-, IIS- oder ASP.NET-Bug entdeckt, der damit zu tun hat, dass dieser Thread-Abbruch-Mechanismus durch eine IL-Optimierung besiegt wird?


Vollständig skripted Repro finden Sie bei https://github.com/jamezor/HttpHandlerRepro für jeden interessierten.

+0

Welche Version von .NET Framework haben Sie verwendet? 4.6.0 ist bekannt, einige Probleme zu haben, und Sie sollten RyuJIT zur Umgehung einiger deaktivieren. –

+0

Wir laufen mit .NET 4.5.2 also kann 4.6 leider nicht beschuldigen :) – Jamezor

Antwort

0

nicht Response.End() zu stoppen Verarbeitung der Anforderung Verwenden Sie, ist es besser HttpApplication.CompleteRequest() zu verwenden. Werfen Sie einen Blick auf diese Beiträge:

+0

Das mag stimmen, aber dann sollte 'Response.End()' den Worker-Prozess nicht abstürzen. – CodeCaster

+0

Ja, das ist die Wahrheit: - /. Ok und haben Sie die Rapid Fail Proctection-Einstellungen für den Anwendungspool in IIS überprüft? Gibt es Standardwerte? Irgendwelche anderen interessanten Ereignisse im Ereignisprotokoll? – Plaz

+0

Wir haben 200k Zeilen von Delphi.Net nach C# migriert, Response.End() wird leider frei verwendet. Aber in jedem Fall, mit nur einer winzigen IL-Änderung (oder einfach kompilieren ohne Optimierungen) arbeitet IIS wie erwartet und stürzt nicht ab, was für mich mögliche Konfigurationsprobleme ausschließt. Und die einzigen Ereignisse im Ereignisprotokoll werden in der Frage angezeigt, andere erscheinen nicht. – Jamezor