ASP.NET应用程序中的Thread.Abort导致w3wp.exe崩溃。

10
不要在此问题上设置重复标记 - 它与“为什么会发生ThreadAbortException”无关,而是与“为什么w3wp.exe进程在ThreadAbortException后终止”有关。
假设我们有一个简单的Web应用程序,并且具有以下代码示例:
protected void Page_Load(object sender, EventArgs e)
{
    Response.Redirect("http://google.com");
}

实际上意味着类似于(见Is Response.End() considered harmful?):

protected void Page_Load(object sender, EventArgs e)
{
    ...response write some data...
    System.Threading.Thread.CurrentThread.Abort();
}
在我的机器上(Windows 10 Pro + IIS),这段代码会导致IIS进程池以0x0错误代码终止(未执行重定向)。在其他机器上(非Windows 10),此代码仅生成ThreadAborted异常,但进程继续工作(执行重定向)。
有人能检查一下这个示例并解释一下发生了什么吗?
更新:以下是与此问题相关的一些Windows事件日志。
日志 #1
未处理的异常错误导致该进程被终止。
应用程序ID:/LM/W3SVC/1/ROOT/AS
进程ID:6700
异常:System.Threading.ThreadAbortException
消息:线程正在被中止。
堆栈跟踪:在System.Web.HttpRuntime.ProcessRequestNotificationPrivate(IIS7WorkerRequest wr, HttpContext context) at 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)
日志 #2
Faulting application name: w3wp.exe, version: 10.0.10240.16384, time stamp: 0x559f3dad
Faulting module name: KERNELBASE.dll, version: 10.0.10240.16384, time stamp: 0x559f3b2a
Exception code: 0xe0434352
Fault offset: 0x000b3e28
Faulting process id: 0x1a2c
Faulting application start time: 0x01d0e4b1b3ed01cb
Faulting application path: C:\WINDOWS\SysWOW64\inetsrv\w3wp.exe
Faulting module path: C:\WINDOWS\SYSTEM32\KERNELBASE.dll
Report Id: 23b5298d-3b36-49c7-a294-de9c864b703f
Faulting package full name: 
Faulting package-relative application ID: 

1
@Nanhydrin,Thread.Abort只是一个示例,用于展示Response.Redirect内部的情况,即Response.Redirect()调用Response.End(),然后调用Thread.Abort()(请参见https://dev59.com/B3NA5IYBdhLWcg3wHp-B)。 - user2440074
2
我也遇到过这个问题,特别是在安装了.Net 4.6之后(不过我还不知道原因)。尽管我的项目没有针对4.6版本进行开发,但是根据这个链接所示,该框架将被使用:http://developers.slashdot.org/story/15/07/28/160255/net-46-optimizer-bug-causes-methods-to-get-wrong-parameters。 - manderson
1
我遇到了完全相同的问题,但我的同事们可以顺利运行完全相同的代码。 - erikkallen
4
不是重复问题。另一个问题是关于为什么Response.End会导致ThreadAbortException,而这个问题是关于为什么ThreadAbortException会导致w3wp出现Win32Exception错误。 - erikkallen
2
你是否已安装RyuJIT的KB更新以修复优化漏洞,或采用绕过方法避免此问题?这篇文章提到使用绕过方法时有类似的情况。http://blogs.msdn.com/b/dotnet/archive/2015/07/28/ryujit-bug-advisory-in-the-net-framework-4-6.aspx - StingyJack
显示剩余11条评论
4个回答

5

我成功地在安装了.NET 4.6的Server 2008r2上重现了这个问题。

我怀疑你们其他人遇到的是同样的问题;线程终止异常会在事件日志中杀死应用程序池(虽然在我的情况下任何未处理的异常都会导致这个问题;但这可能只是全局异常处理程序捕获它并使用Response.End或Redirect结束了它)。 转储堆栈跟踪也与Ian的答案相匹配。

已经为此问题开了一个MS Connect票,最近的KB补丁为我解决了这个问题。

Connect文章:https://connect.microsoft.com/VisualStudio/feedback/details/1605438/disabling-ryujit-breaks-asp-net

KB补丁:https://support.microsoft.com/en-us/kb/3098786


4

到目前为止,我只有一个解决方案:

    static class WebExtensions
    {
        public static void EndSafe(this HttpResponse response)
        {
            response.Flush();
            response.SuppressContent = true;
            HttpContext.Current.ApplicationInstance.CompleteRequest();
        }

        public static void RedirectSafe(this HttpResponse response, string url)
        {
            response.Redirect(url, false);
            HttpContext.Current.ApplicationInstance.CompleteRequest();
        }
    }

然而,这迫使我确保在此之后不会执行任何代码:

...some code
response.RedirectSafe(url);
return; //<-- important
...some more code

请注意,在某些情况下仅使用“return”是不够的(例如在递归调用中),有时您可能需要避免使用“return”(使用try-finally结构)


我认为这只是掩盖了问题,你对于质疑为什么ThreadAbortException会一直崩溃到w3wp.exe是正确的。我目前正在诊断一个类似的问题,这是在升级到.NET 4.6之后出现的。 - Jordan Rieger
升级到IIS 8和.NET 4.6后遇到了同样的问题。在Application_BeginRequest内调用Response.Redirect()会导致整个进程崩溃。这段代码解决了这个问题。在IIS 7上我们没有遇到过这个问题。 - JDub

2
我今天在Windows 8.1上遇到了完全相同的问题,在重启安装Windows更新后出现了这个问题。
问题是,我手动在注册表中禁用了RyuJIT,由于此问题,通过添加useLegacyJit DWORD并将其设置为1(参见方法#3)。但其中一个更新在相同位置创建了UseRyuJIT键,并将其设置为1,这显然使ASP.NET非常困惑。
解决方案是将useLegacyJit设置为0并发出iisreset。之后,世界一切正常。
当我调试w3wp.exe转储时,WinDbg的!clrstack显示了以下帧。也许这会帮助其他遇到相同错误且正在寻找解决方案的人:
000000ef9892be98 00007ffa0e2d1fea [HelperMethodFrame: 000000ef9892be98] 
000000ef9892bf80 00007ff99d776588 System.Web.Hosting.PipelineRuntime.ProcessRequestNotification(IntPtr, IntPtr, IntPtr, Int32)
000000ef9892df90 00007ff9fc172345 [FaultingExceptionFrame: 000000ef9892df90] 
000000ef9892e490 00007ff99d7796c0 System.Web.HttpRuntime.ProcessRequestNotificationPrivate(System.Web.Hosting.IIS7WorkerRequest, System.Web.HttpContext)
000000ef9892e520 00007ff99d777377 System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper(IntPtr, IntPtr, IntPtr, Int32)
000000ef9892e700 00007ff99d77655a System.Web.Hosting.PipelineRuntime.ProcessRequestNotification(IntPtr, IntPtr, IntPtr, Int32)
000000ef9892e740 00007ff99d775c11 DomainNeutralILStubClass.IL_STUB_ReversePInvoke(Int64, Int64, Int64, Int32)
000000ef9892ef58 00007ff9fc100b4e [InlinedCallFrame: 000000ef9892ef58] System.Web.Hosting.UnsafeIISMethods.MgdIndicateCompletion(IntPtr, System.Web.RequestNotificationStatus ByRef)
000000ef9892ef58 00007ff99d78cc1b [InlinedCallFrame: 000000ef9892ef58] System.Web.Hosting.UnsafeIISMethods.MgdIndicateCompletion(IntPtr, System.Web.RequestNotificationStatus ByRef)
000000ef9892ef30 00007ff99d78cc1b DomainNeutralILStubClass.IL_STUB_PInvoke
000000ef9892f000 00007ff99d77756c System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper(IntPtr, IntPtr, IntPtr, Int32)
000000ef9892f1e0 00007ff99d77655a System.Web.Hosting.PipelineRuntime.ProcessRequestNotification(IntPtr, IntPtr, IntPtr, Int32)
000000ef9892f220 00007ff99d775c11 DomainNeutralILStubClass.IL_STUB_ReversePInvoke(Int64, Int64, Int64, Int32)
000000ef9892f418 00007ff9fc100da3 [ContextTransitionFrame: 000000ef9892f418]

1
谢谢你提供的堆栈跟踪信息,这正是让我找到了这里,并确认其他人也在遇到同样的问题,这让我知道我并不是疯了。 - MisterZimbu
@MisterZimbu 很高兴我能帮到你! - Ian Kemp

0

我在Win7 SP1上遇到了同样的问题。Web应用程序编译目标为.net 4.5.2,并在.net 4.6上运行。我没有改变useLegacyJit或useRyuJIT注册表标志。

结果发现我的应用程序域中“启用32位应用程序”不必要地被设置为已启用。禁用它修复了这个问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接