SEHException未被Try/Catch捕获

And*_*eas 12 .net vb.net exception seh

在后台线程中,我的应用程序会定期检查网络文件夹(UNC路径)以获取应用程序更新.它会读出文件的汇编版本,如下所示:

Try
    newVers = System.Reflection.AssemblyName.GetAssemblyName("\\server\app.exe").Version
Catch ex As Exception
    ' ignore
End Try
Run Code Online (Sandbox Code Playgroud)

这段代码经常被执行,到目前为止我总共在多个客户站点猜测超过100.000次没有问题.

有时GetAssemblyName会引发a FileNotFoundException,例如万一网络文件夹无法访问(可能发生并且必须处理).这个异常被Catch下面的块捕获,一切正常.

然而,在三个报告的案例中,GetAssemblyName电话提出了一个SEHException.奇怪的是,这个异常并没有被Catch下面的块捕获,而是被我的全局未处理异常处理程序(System.AppDomain.CurrentDomain.UnhandledException)捕获.结果,应用程序崩溃.

这是异常细节(遗憾的是,我的错误处理例程没有记录异常的ErrorCodeCanResume字段):

Caught exception: System.Runtime.InteropServices.SEHException
   Message: External component has thrown an exception.
   Source: mscorlib
   TargetSite: System.Reflection.AssemblyName nGetFileInformation(System.String)
   StackTrace: 
      at System.Reflection.AssemblyName.nGetFileInformation(String s)
      at System.Reflection.AssemblyName.GetAssemblyName(String assemblyFile)
      at SyncThread.Run() 
      at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
      at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
      at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
      at System.Threading.ThreadHelper.ThreadStart()
Run Code Online (Sandbox Code Playgroud)

为什么Catch下面的块没有捕获异常?

(也许这是相关的:这只发生在客户站点上,其中UNC路径指向不属于本地网络的服务器,而是VPN上的远程服务器.)

por*_*ges 15

从.NET 4开始,一些SEHExceptions指示损坏的进程状态,并被称为"损坏的状态异常".这些是诸如段错误/访问冲突之类的事情,其中​​在检测到内存损坏后抛出异常.

虽然这些错误仍然映射回托管.NET SEHExceptions,但默认情况下它们不可捕获,因此try { ... } catch (Exception ex) { ... }无法处理它们.

您可以选择处理这些异常(通过应用程序配置文件中的属性或策略更改),但不建议这样做,因为您的程序现在可以处理无效数据:

CLR始终使用与程序本身引发的异常相同的机制向托管代码提供SEH异常.只要代码不尝试处理无法合理处理的异常条件,这就不是问题.在访问冲突后,大多数程序无法安全地继续执行.不幸的是,CLR的异常处理模型总是鼓励用户通过允许程序捕获System.Exception层次结构顶部的任何异常来捕获这些严重错误.但这很少是正确的做法.

写入捕获(异常e)是一种常见的编程错误,因为未处理的异常会产生严重后果.但是你可能会争辩说,如果你不知道函数会引发什么错误,你应该在程序调用该函数时防止所有可能的错误.这似乎是一个合理的行动方案,直到您考虑在您的流程可能处于损坏状态时继续执行意味着什么.有时中止和再次尝试是最好的选择:没有人喜欢看Watson对话框,但重启程序比让数据损坏更好.

程序捕获由他们不理解的上下文引起的异常是一个严重的问题.但是,您无法通过使用异常规范或其他合同机制来解决问题.由于CLR是多种应用程序和主机的平台,因此托管程序能够接收SEH异常通知非常重要.某些主机(如SQL Server)需要完全控制其应用程序的进程.与本机代码互操作的托管代码有时必须处理本机C++异常或SEH异常.

但是大多数编写catch(异常e)的程序员并不真正想要捕获访问冲突.他们宁愿在发生灾难性错误时停止执行程序,而不是让程序在未知状态下跛行.对于托管托管加载项(如Visual Studio或Microsoft Office)的程序尤其如此.如果加载项导致访问冲突,然后吞下异常,则主机可能会损坏自己的状态(或用户文件),而不会发现出现问题.

来自(在MSDN杂志中)引用的文章更详细.

如果您决定处理这些异常,则需要考虑很多 - 正如文章所述:"编写处理CSE的正确代码并继续安全地运行流程非常困难."

特别是,finally异常已经过去的任何块都没有被执行(因此,例如,任何文件句柄都悬空直到收集),甚至可以跳过约束执行区!


此外,您可能应该将此报告为Microsoft的错误,因为GetAssemblyName不应该抛出此类异常.