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.
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. –
Wir laufen mit .NET 4.5.2 also kann 4.6 leider nicht beschuldigen :) – Jamezor