2016-08-02 34 views
0

優化拍攝模式我有一個HttpHandler的,看起來像這樣:C#HttpHandler的崩潰IIS - 但只有在與

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; 
} 

它的偉大工程!除了在發佈模式下編譯並啓用了優化並隨後執行(在運行帶有.NET 4.5.2的IIS 8的Windows Server 2012上)之外。然後它崩潰IIS。

發生未處理的異常,並且進程終止。

應用程序ID:/ LM/W3SVC/1592535739/ROOT/HttpHandlerApp

進程ID:648

例外:System.Threading.ThreadAbortException

消息:線程已被中止。

堆棧跟蹤:在System.Web.HttpRuntime.ProcessRequestNotificationPrivate(IIS7WorkerRequest WR,HttpContext的上下文)

在System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper(IntPtr的rootedObjectsPointer,IntPtr的nativeRequestContext,IntPtr的moduleData,的Int32標誌)

在System.Web.Hosting.PipelineRuntime.ProcessRequestNotification(IntPtr的rootedObjectsPointer,IntPtr的nativeRequestContext,IntPtr的moduleData,的Int32標誌)

錯誤的應用程序名:w3wp.exe,版本:8.0.9200.16384,時間戳:0x50108835

錯誤模塊名稱:KERNELBASE.dll,版本:6.2.9200.17366,時間戳:0x554d4531

異常代碼:0xe0434352

故障偏移:0x000000000004aea8

出錯進程ID:0x288

錯誤的應用程序的開始時間:0x01d1ec2c7db735a6

錯誤的應用程序路徑:C:\ Windows \ System32下\ INETSRV \ w3wp.exe的

錯誤模塊路徑:C:\ Windows \ System32下\ KERNELBASE.dll

報告編號:bb7471fa-581f-11e6-93f1-00155d461b1c

斷裂作用包全名:

斷裂作用包相對應用程序ID:

我已經縮小了問題的範圍,即在啓用/禁用優化時更改的IL的特定位。

這裏是IL爲ProcessRequest不崩潰IIS:

.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 

爲了使IIS崩潰,變更線19

 IL_000e: leave.s IL_001d 

這種變化直接使嵌套catch塊退出到方法返回指令,而不訪問try..finally的try塊中剩餘的單個指令。

我的假設是,崩潰與ThreadAbortException(其中一個context.Response.End()將拋出)的魔術自動重投行爲有關,以及CLR和/或IIS和/或ASP.NET如何管理該行爲;所以當優化的IL從catch塊直接退出到返回指令時,在IL_0010處插入的CLR/IIS/ASP.NET錯過了一些假想的中止重置魔術,並且ThreadAbortException取消了整個IIS。

還有散落在互聯網這個行爲(例如these msdn docs狀態ThreadAbortException is a special exception that can be caught, but it will automatically be raised again at the end of the catch block.this blog提到... 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.)線索,但我無法找到任何具體的有關機制。

所以我想我的問題是:這是怎麼回事?我是否真的發現CLR或IIS或ASP.NET錯誤與這種線程中止機制被IL優化擊敗?


對於任何感興趣的人,可以在https://github.com/jamezor/HttpHandlerRepro找到完全腳本的repro。

+0

您使用的是哪個版本的.NET Framework? 4.6.0已知有一些問題,您應該禁用RyuJIT來解決一些問題。 –

+0

我們正在使用.NET 4.5.2運行,所以不能責怪4.6不幸的是:) – Jamezor

回答

0

不要使用到Response.End()停止處理該請求,這是更好地使用HttpApplication.CompleteRequest()。看看這些帖子:

+0

這可能是真的,但是仍然是'Response.End()'不應該使工作進程崩潰。 – CodeCaster

+0

是的,這是真的: - /。好的,你有沒有檢查IIS中的應用程序池的快速失敗Proctection設置?有默認值嗎?事件日誌中的其他有趣事件? – Plaz

+0

我們已經從Delphi.Net遷移200k行到C#,不幸的是使用了Response.End()。但無論如何,只有一個微小的IL更改(或者只是編譯沒有優化),IIS按預期工作,並且不會崩潰,從而排除了任何可能的配置問題。事件日誌中的唯一事件顯示在問題中,沒有其他人出現。 – Jamezor