SEHException未被Try / Catch捕获

时间:2013-05-08 09:04:39

标签: .net vb.net exception seh

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

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

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

有时,GetAssemblyName会引发FileNotFoundException,例如万一网络文件夹无法访问(可能会发生并且必须处理)。

但是,在三个报告的案例中,Catch调用引发了GetAssemblyName。奇怪的是,这个异常并没有被下面的SEHException块捕获,而是被我的全局未处理的异常处理程序(Catch)捕获。结果,应用程序崩溃。

以下是异常详细信息(遗憾的是,我的错误处理例程未记录异常的System.AppDomain.CurrentDomain.UnhandledExceptionErrorCode字段):

CanResume

为什么异常不会被下面的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() 块捕获?

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

1 个答案:

答案 0 :(得分:15)

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

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

您可以选择加入处理这些例外(via an attribute or a policy change in your app's config file),但不建议这样做,因为您的程序现在可能正在处理无效数据:

  

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

     

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

     

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

     

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

The article this quote is from (in MSDN magazine)更详细。

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

特别是,异常传递的任何finally块都已执行 (因此,例如,任何文件句柄在收集之前都悬空),甚至constrained execution regions可能会被跳过!


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