问题描述
在后台线程中,我的应用程序会定期检查网络文件夹(UNC Path)以进行应用程序更新。它读出该文件的汇编版本,如下所示:
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:
Try
newVers = System.Reflection.AssemblyName.GetAssemblyName("\\server\app.exe").Version
Catch ex As Exception
' ignore
End Try
这个代码片段经常执行,总共来说,我猜想在多个客户网站上的方式超过了100.000次,没有问题。
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.
有时, GetAssemblyName
引发一个 FileNotFoundException
万一网络文件夹不可达(可能发生并且必须处理)。这个异常被下面的 Catch
块所捕获,一切都正常。
Sometimes, GetAssemblyName
raises 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 Catch
block just below, and everything works just fine.
在三起报告的情况下,但是, GetAssemblyName
调用了一个 SEHException
。奇怪的是,这个异常没有被下面的 Catch
块捕获,而是由我的全局未处理的异常处理程序( System.AppDomain.CurrentDomain)捕获。 UnhandledException
)。因此,应用程序崩溃。
In three reported cases, however, the GetAssemblyName
call raised an SEHException
. The strange thing is that this exception was not caught by the Catch
block just below, but by my global unhandled exception handler (System.AppDomain.CurrentDomain.UnhandledException
). As a result, the application crashes.
以下是异常详细信息(不幸的是, ErrorCode
和 CanResume
异常字段未被我的错误处理例程记录):
Here is the exception detail (unfortunately, the ErrorCode
and CanResume
fields of the exception are not logged by my error handling routine):
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()
为什么这个例外不被 Catch捕获? $ c>块刚好在下面?
Why is is that the exception is not caught by the Catch
block just below?
(可能这是相关的:这只是在客户站点发生,UNC路径指向不属于本地网络,但VPN上的远程服务器。)
(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.)
推荐答案
自.NET 4以来,一些 SEHException
s表示已损坏的进程状态,称为已损坏状态异常。这些是segfaults /访问冲突,其中在检测到内存损坏之后抛出异常。
Since .NET 4, some SEHException
s 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 SEHExceptions
,它们在默认情况下不可以收看,所以 try {...} catch(Exception ex){...}
won不能处理它们。
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.
您可以选择处理这些异常(),但不推荐,因为您的程序现在可以处理无效数据:
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:
编写catch(异常e)是一个常见的编程错误,因为未处理的异常有严重的后果。但是您可能会认为,如果您不知道某个函数会引发哪些错误,那么在程序调用该函数时,您应该保护所有可能的错误。这似乎是一个合理的行动过程,直到您想到当进程可能处于损坏状态时继续执行的意义。有时候中止并尝试再次是最好的选择:没有人喜欢看到沃森对话框,但最好重新启动程序,而不是使您的数据损坏。
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.
程序捕获异常由于他们不了解的背景,是一个严重的问题。但是您不能通过使用异常规范或其他一些契约机制来解决问题。由于CLR是多种应用程序和主机的平台,因此托管程序能够接收到SEH异常的通知很重要。某些主机(如SQL Server)需要完全控制其应用程序的进程。与本地代码进行互操作的托管代码有时必须处理本地C ++异常或SEH异常。
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.
但是大多数编写catch(Exception e)的程序员并不真的想抓住访问冲突。他们喜欢当发生灾难性错误时停止程序的执行,而不是让程序处于未知状态。对于托管受管加载项(如Visual Studio或Microsoft Office)的程序,这一点尤其如此。如果加载项导致访问冲突,然后吞下异常,则主机可能会对其自己的状态(或用户文件)造成损害,而不会发现出现问题。
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.
进行了更多的细节。
如果你决定处理这些例外,有很多事要考虑 - 正如文章所说的难以编写处理CSE的正确代码,并继续安全运行。
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."
特别是,任何终于
异常已经过去的块已经执行了不(所以,例如任何文件句柄悬挂直到收集),甚至可能会被跳过!
In particular, any finally
blocks that the exception has passed over have not been executed (so, e.g. any file handles are dangling until collected), and even constrained execution regions may be skipped!
此外,你应该可以将这报告为Microsoft的错误,因为 GetAssemblyName
不应该抛出这种异常。
In addition, you should probably report this as a bug to Microsoft, as GetAssemblyName
shouldn't be throwing this kind of exception.
这篇关于SEHException未被Try / Catch捕获的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!