C#HttpHandler崩溃了IIS - 但仅在发布模式下,

时间:2016-08-02 02:11:20

标签: c# asp.net iis httphandler

我有一个看起来像这样的HttpHandler:

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

     

消息:线程正在中止。

     

StackTrace:在System.Web.HttpRuntime.ProcessRequestNotificationPrivate(IIS7WorkerRequest wr,HttpContext context)

     

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

     

at System.Web.Hosting.PipelineRuntime.ProcessRequestNotification(IntPtr rootedObjectsPointer,IntPtr nativeRequestContext,IntPtr moduleData,Int32 flags)

  

错误应用程序名称: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

     

报告ID:bb7471fa-581f-11e6-93f1-00155d461b1c

     

错误包全名:

     

错误包相关的应用程序ID:

我已将问题缩小到特定的IL位,在启用/禁用优化时会发生变化。

以下是ProcessRequest的IL,它不会导致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块退出到返回指令时,CLR / IIS / ASP.NET在IL_0010插入的一些假设的中止重置魔术会被错过,而ThreadAbortException会占用整个IIS。

互联网上散布着关于此行为的线索(例如these msdn docsThreadAbortException 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.)但我找不到任何关于该机制的具体内容。< / p>

所以我想我的问题是:这里发生了什么?我是否真的发现CLR或IIS或ASP.NET漏洞与IL优化失败的线程中止机制有关?

对于任何感兴趣的人,都可以在https://github.com/jamezor/HttpHandlerRepro找到完全脚本化的repro。

1 个答案:

答案 0 :(得分:0)

请勿使用 Response.End()停止处理请求,最好使用 HttpApplication.CompleteRequest()。看看这些帖子: