优化拍摄模式我有一个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。
您使用的是哪个版本的.NET Framework? 4.6.0已知有一些问题,您应该禁用RyuJIT来解决一些问题。 –
我们正在使用.NET 4.5.2运行,所以不能责怪4.6不幸的是:) – Jamezor