【问题标题】:Catching a StackOverflowException捕获 StackOverflowException
【发布时间】:2010-08-30 02:24:26
【问题描述】:

如何捕捉StackOverflowException

我有一个允许用户编写脚本的程序,当运行任意用户代码时,我可能会得到一个StackOverflowException。运行用户代码的那块明显被try-catch包围了,但是一般情况下栈溢出是无法捕获的。

我环顾四周,this 是我能找到的最有用的答案,但仍然让我陷入了死胡同;从article in the BCL team's blog 我发现我应该使用RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup 调用代码和即使在堆栈溢出后也会被调用的委托,但是在尝试时,进程会因堆栈溢出消息而终止,而不会调用委托.我尝试在处理程序方法上添加PrePrepareMethodAttribute,但这并没有改变任何东西。

我也尝试过使用 AppDomain 并同时处理 UnhandledExceptionDomainUnload 事件 - 但整个进程在堆栈溢出时被终止。即使我手动 throw new StackOverflowException(); 并且没有得到实际的堆栈溢出,也会发生同样的情况。

【问题讨论】:

  • 您是否有可以使用脚本自动执行某些任意过程的程序,或者您的程序是脚本的文本编辑器?您的“任意用户代码”本身是脚本还是某种 IL 插件?
  • 现在我的程序是该语言的 REPL(读取-评估-打印循环)。

标签: c# stack-overflow


【解决方案1】:

要处理您的代码未处理的异常,您可以订阅 AppDomains UnhandledException - 这是操作系统在显示程序意外退出的对话框时处理的内容。

在程序的 Main 方法中使用

var currentDomain = AppDomain.CurrentDomain;

然后为事件添加一个处理程序

currentDomain.UnhandledException += 处理程序;

在处理程序中,您可以做任何您想做的事情,例如记录、显示错误,甚至在需要时重新初始化程序。

【讨论】:

  • 你说得对,这是我尝试的第一件事——但没有奏效。我已将其添加到问题中。
【解决方案2】:

对脚本引擎进行编程以跟踪脚本中的递归级别。如果递归超出某个任意大的数字,则在脚本终止程序之前终止脚本。或者,您可以对脚本引擎进行编程,使其以无堆栈方式运行,并将脚本的所有堆栈数据存储在 System.Collections.Generic.Stack 中。即使您确实使用了单独的堆栈,您仍然希望限制脚本可以具有的递归级别,但堆栈集合将为您提供数百倍的堆栈空间。

【讨论】:

  • 听起来他在运行原始 IL,而不是他自己的解释器。
  • 事实上,我正在运行自己的解释器。但如果可能的话,我想要一个也适用于原始 IL 的解决方案。
  • 另外,脚本可以调用任何 .net 函数——这意味着我不能很好地保护调用路径。
【解决方案3】:

您需要在单独的进程中运行代码。

【讨论】:

  • 那么用户仍然会看到进程崩溃,包括在这种情况下发生的烦人的 Windows 屏幕。我如何从父进程中检测到这种情况以防止这种情况发生?
【解决方案4】:

您必须在不同的应用程序域中加载用户脚本或任何外部 3rd 方插件,以便在发生不可恢复的错误时安全地卸载域。

您必须创建一个不同的AppDomain,因为您无法从加载的域中卸载程序集,并且您不想关闭您的主应用程序域。

您像这样创建一个新的应用程序域:

var scriptDomain = AppDomain.CreateDomain("User Scripts");

然后您可以从您需要创建的程序集中加载任何类型。您必须确保要加载的对象继承自 MarshalByRefObject

我假设您的用户脚本被包装在这样定义的对象中:

public abstract UserScriptBase : MarshaByRefObject
{
    public abstract void Execute();
}

因此,您可以像这样加载任何用户脚本:

object script = domain.CreateInstanceFromAndUnwrap(type.Location, type.FullName);

毕竟,您可以订阅scriptDomain.UnhandledException 并监控任何不可恢复的错误。

使用不同的应用程序域并不容易,您很可能会遇到一些加载/卸载问题(DLL 被两个域引用)。

我推荐你在网上找到的some tutorial

【讨论】:

  • 这无济于事。 StackOverflowException 终止整个进程,不管它发生在哪个AppDomain
  • @configurator,如果它不起作用,那是个好主意吗?也许它很聪明或复杂,但不是很好。
  • @joao 并非所有好主意都能实现。有时,尝试某事的想法是好的,即使它不起作用。你从来没有尝试过,你成功了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-12-17
  • 1970-01-01
  • 1970-01-01
  • 2013-01-31
  • 2019-01-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多