vb.net Try/Catch 未捕获 SEHException
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16436597/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
SEHException not caught by Try/Catch
提问by Andreas
In a background thread, my application regularly examines a network folder (UNC Path) for application updates. It reads out the assembly version of the file, like so:
在后台线程中,我的应用程序会定期检查网络文件夹(UNC 路径)以获取应用程序更新。它读出文件的汇编版本,如下所示:
Try
newVers = System.Reflection.AssemblyName.GetAssemblyName("\server\app.exe").Version
Catch ex As Exception
' ignore
End Try
This snippet is executed quite often, in total I'd guess way more than 100.000 times on multiple customer sites so far without a problem.
这段代码经常执行,到目前为止,我猜在多个客户站点上总共执行了 100.000 多次,没有任何问题。
Sometimes, GetAssemblyNameraises a FileNotFoundException, for instance in case the network folder is not reachable (which can happen and must be dealt with). This exception is caught by the Catchblock just below, and everything works just fine.
有时,GetAssemblyName会引发FileNotFoundException,例如在网络文件夹不可访问的情况下(可能发生并且必须处理)。这个异常被Catch下面的块捕获,一切正常。
In three reported cases, however, the GetAssemblyNamecall raised an SEHException. The strange thing is that this exception was not caught by the Catchblock just below, but by my global unhandled exception handler (System.AppDomain.CurrentDomain.UnhandledException). As a result, the application crashes.
然而,在三个报告的案例中,该GetAssemblyName电话引发了SEHException. 奇怪的是,这个异常没有被Catch下面的块捕获,而是被我的全局未处理异常处理程序 ( System.AppDomain.CurrentDomain.UnhandledException)捕获。结果,应用程序崩溃。
Here is the exception detail (unfortunately, the ErrorCodeand CanResumefields of the exception are not logged by my error handling routine):
这是异常详细信息(不幸的是,我的错误处理例程没有记录异常的ErrorCode和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()
Why is is that the exception is not caught by the Catchblock just below?
为什么Catch下面的块没有捕获异常?
(Maybe this is relevant: this has only happened on customer sites, where the UNC path pointed to a server that was not part of the local network, but a remote server on a VPN.)
(也许这是相关的:这仅发生在客户站点上,其中 UNC 路径指向的服务器不属于本地网络,而是 VPN 上的远程服务器。)
回答by porges
Since .NET 4, some SEHExceptions indicate corrupted process states, and are termed "corrupted state exceptions". These are things like segfaults/access violations, where the exception is thrown after memory corruption has been detected.
从 .NET 4 开始,一些SEHExceptions 表示损坏的进程状态,并被称为“损坏状态异常”。这些是诸如段错误/访问冲突之类的事情,在检测到内存损坏后抛出异常。
While these errors are still mapped back to managed .NET SEHExceptions, they are not catchable by default, so try { ... } catch (Exception ex) { ... }won't handle them.
虽然这些错误仍然映射回托管 .NET SEHExceptions,但默认情况下它们无法捕获,因此try { ... } catch (Exception ex) { ... }不会处理它们。
You can opt-in to handling these exceptions (either via an attribute or a policy change in your app's config file), but it is not recommended, as your program could now be processing invalid data:
您可以选择处理这些异常(通过应用程序配置文件中的属性或策略更改),但不建议这样做,因为您的程序现在可能正在处理无效数据:
The CLR has always delivered SEH exceptions to managed code using the same mechanisms as exceptions raised by the program itself. This isn't a problem as long as code doesn't attempt to handle exceptional conditions that it cannot reasonably handle. Most programs cannot safely continue execution after an access violation. Unfortunately, the CLR's exception handling model has always encouraged users to catch these serious errors by allowing programs to catch any exception at the top of the System.Exception hierarchy. But this is rarely the right thing to do.
Writing catch (Exception e) is a common programming error because unhandled exceptions have serious consequences. But you might argue that if you don't know what errors will be raised by a function, you should protect against all possible errors when your program calls that function. This seems like a reasonable course of action until you think about what it means to continue execution when your process is possibly in a corrupted state. Sometimes aborting and trying again is the best option: nobody likes to see a Watson dialog, but it's better to restart your program than to have your data corrupted.
Programs catching exceptions arising from contexts they don't understand is a serious problem. But you can't solve the problem by using exceptions specifications or some other contract mechanism. And it's important that managed programs be able to receive notification of SEH exceptions because the CLR is a platform for many kinds of applications and hosts. Some hosts, such as SQL Server, need to have total control of their application's process. Managed code that interoperates with native code sometimes must deal with native C++ exceptions or SEH exceptions.
But most programmers who write catch (Exception e) don't really want to catch access violations. They'd prefer that execution of their program stops when a catastrophic error occurs rather than letting the program limp along in an unknown state. This is especially true for programs that host managed add-ins such as Visual Studio or Microsoft Office. If an add-in causes an access violation and then swallows the exception, the host could be doing damage to its own state (or user files) without ever realizing something went wrong.
CLR 始终使用与程序本身引发的异常相同的机制将 SEH 异常传递给托管代码。只要代码不尝试处理它无法合理处理的异常情况,这就不是问题。大多数程序在访问冲突后不能安全地继续执行。不幸的是,CLR 的异常处理模型一直鼓励用户通过允许程序捕获 System.Exception 层次结构顶部的任何异常来捕获这些严重错误。但这很少是正确的做法。
编写 catch (Exception e) 是一种常见的编程错误,因为未处理的异常会带来严重的后果。但是您可能会争辩说,如果您不知道某个函数会引发什么错误,那么您应该在程序调用该函数时防止所有可能的错误。这似乎是一个合理的行动方案,直到您考虑在您的流程可能处于损坏状态时继续执行意味着什么。有时中止并重试是最好的选择:没有人喜欢看到 Watson 对话框,但最好重新启动程序而不是损坏数据。
程序捕获由他们不理解的上下文引起的异常是一个严重的问题。但是你不能通过使用异常规范或其他一些契约机制来解决问题。受管程序能够接收 SEH 异常通知很重要,因为 CLR 是适用于多种应用程序和主机的平台。某些主机(例如 SQL Server)需要完全控制其应用程序的进程。与本机代码互操作的托管代码有时必须处理本机 C++ 异常或 SEH 异常。
但是大多数编写 catch (Exception e) 的程序员并不真正想要捕获访问冲突。他们更愿意在发生灾难性错误时停止执行程序,而不是让程序在未知状态下跛行。对于托管 Visual Studio 或 Microsoft Office 等托管加载项的程序尤其如此。如果加载项导致访问冲突,然后吞下异常,则主机可能会损坏自己的状态(或用户文件),而从未意识到出现问题。
The article this quote is from (in MSDN magazine)goes into much more detail.
If you do decide to handle these exceptions, there is a lot to consider - as the article states "It's very difficult to write correct code that handles a CSE and continues running the process safely."
如果您确实决定处理这些异常,则需要考虑很多因素 - 正如文章所述:“编写正确的代码来处理 CSE 并继续安全地运行该过程是非常困难的。”
In particular, any finallyblocks that the exception has passed over have notbeen executed (so, e.g. any file handles are dangling until collected), and even constrained execution regionsmay be skipped!
特别是,finally异常传递的任何块都没有被执行(因此,例如,任何文件句柄在收集之前都是悬空的),甚至可能会跳过受约束的执行区域!
In addition, you should probably report this as a bug to Microsoft, as GetAssemblyNameshouldn't be throwing this kind of exception.
此外,您可能应该将此作为错误报告给 Microsoft,因为GetAssemblyName不应该抛出此类异常。

