简体   繁体   English

C#HttpHandler崩溃了IIS - 但仅在发布模式下进行了优化

[英]C# HttpHandler crashes IIS - but only in Release mode with optimizations on

I have a HttpHandler which looks like this: 我有一个看起来像这样的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;
}

It works great! 它很棒! Except when compiled in Release mode with optimizations enabled and then executed (on Windows Server 2012 running IIS 8 with .NET 4.5.2). 除非在发布模式下编译并启用优化然后执行(在运行带有.NET 4.5.2的IIS 8的Windows Server 2012上)。 Then it crashes IIS. 然后它崩溃了IIS。

An unhandled exception occurred and the process was terminated. 发生了未处理的异常,并终止了该过程。

Application ID: /LM/W3SVC/1592535739/ROOT/HttpHandlerApp 应用程序ID:/ LM / W3SVC / 1592535739 / ROOT / HttpHandlerApp

Process ID: 648 进程ID:648

Exception: System.Threading.ThreadAbortException 例外:System.Threading.ThreadAbortException

Message: Thread was being aborted. 消息:线程正在中止。

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

at System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper(IntPtr rootedObjectsPointer, IntPtr nativeRequestContext, IntPtr moduleData, Int32 flags) 在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) 在System.Web.Hosting.PipelineRuntime.ProcessRequestNotification(IntPtr rootedObjectsPointer,IntPtr nativeRequestContext,IntPtr moduleData,Int32 flags)

and

Faulting application name: w3wp.exe, version: 8.0.9200.16384, time stamp: 0x50108835 错误应用程序名称:w3wp.exe,版本:8.0.9200.16384,时间戳:0x50108835

Faulting module name: KERNELBASE.dll, version: 6.2.9200.17366, time stamp: 0x554d4531 错误模块名称:KERNELBASE.dll,版本:6.2.9200.17366,时间戳:0x554d4531

Exception code: 0xe0434352 异常代码:0xe0434352

Fault offset: 0x000000000004aea8 故障偏移:0x000000000004aea8

Faulting process id: 0x288 错误进程id:0x288

Faulting application start time: 0x01d1ec2c7db735a6 错误应用程序启动时间:0x01d1ec2c7db735a6

Faulting application path: c:\\windows\\system32\\inetsrv\\w3wp.exe 错误的应用程序路径:c:\\ windows \\ system32 \\ inetsrv \\ w3wp.exe

Faulting module path: C:\\Windows\\system32\\KERNELBASE.dll 错误模块路径:C:\\ Windows \\ system32 \\ KERNELBASE.dll

Report Id: bb7471fa-581f-11e6-93f1-00155d461b1c 报告编号:bb7471fa-581f-11e6-93f1-00155d461b1c

Faulting package full name: 错误包全名:

Faulting package-relative application ID: 错误包相关的应用程序ID:

I have narrowed the issue down to a particular bit of IL which changes when optimization is enabled/disabled. 我已经将问题缩小到IL的特定位,当启用/禁用优化时,IL会发生变化。

Here is the IL for ProcessRequest which does not crash IIS: 以下是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

To make IIS crash, change line 19 to 要使IIS崩溃,请将第19行更改为

        IL_000e:  leave.s    IL_001d

This change makes the nested catch block exit directly to the method return instruction without visiting the single instruction remaining in the try block of the try..finally. 此更改使嵌套的catch块直接退出到方法返回指令,而不访问try..finally的try块中剩余的单个指令。

My hypothesis is that the crash relates to the magic auto-rethrow behaviour of ThreadAbortException (one of which context.Response.End() will throw) and how the CLR and/or IIS and/or ASP.NET manages that; 我的假设是崩溃与ThreadAbortException (其中一个context.Response.End()将抛出)以及CLR和/或IIS和/或ASP.NET如何管理它的魔法自动重新抛出行为有关; and so when the optimised IL exits from the catch block directly to the return instruction, some hypothetical abort reset magic which the CLR/IIS/ASP.NET slotted in at IL_0010 gets missed out and the ThreadAbortException takes down the whole of IIS. 因此,当优化的IL直接从catch块退出到返回指令时,CLR / IIS / ASP.NET在IL_0010插入的一些假设的中止重置魔法会被错过,而ThreadAbortException会占用整个IIS。

There are clues scattered around the internet about this behaviour (eg these msdn docs state ThreadAbortException is a special exception that can be caught, but it will automatically be raised again at the end of the catch block. and this blog mentions ... 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. ) but I cannot find anything concrete about the mechanism. 互联网上有关于这种行为的线索(例如, 这些msdn文档状态ThreadAbortException is a special exception that can be caught, but it will automatically be raised again at the end of the catch block. 这个博客提到... 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. )但我找不到任何关于该机制的具体内容。

So I guess my question is: what is going on here? 所以我想我的问题是:这里发生了什么? Have I really discovered a CLR or IIS or ASP.NET bug to do with this thread abort mechanism being defeated by an IL optimisation? 我是否真的发现CLR或IIS或ASP.NET漏洞与IL优化失败的线程中止机制有关?


Fully scripted repro can be found at https://github.com/jamezor/HttpHandlerRepro for anyone interested. 对于任何感兴趣的人,都可以在https://github.com/jamezor/HttpHandlerRepro找到完全脚本化的repro。

Don't use Response.End() to stop processing the request, it's better to use HttpApplication.CompleteRequest() . 不要使用Response.End()来停止处理请求,最好使用HttpApplication.CompleteRequest() Take a look at these posts: 看看这些帖子:

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM