【问题标题】:Disable Window's automated handling of errors in subprocesses禁用 Windows 自动处理子进程中的错误
【发布时间】:2010-09-17 12:54:47
【问题描述】:

我正在尝试为编译器 (LLVM) 编写一个测试套件,它可以在除 Windows 之外的所有平台上完美运行。在 Windows 上,我收到“严重错误处理程序”消息框,它会无限期地停止测试。

这个问题使得测试变得非常困难,因为对于编译器,问题通常意味着汇编级别的无效代码,从而导致疯狂的、不可预测的错误。

我在寻找答案时找到了During a subprocess call, catch critical windows errors in Python instead of letting the OS handle it by showing nasty error pop-ups,但这对我不起作用。测试时我仍然会收到消息框。

[SetErrorMode](http://msdn.microsoft.com/en-us/library/ms680621(VS100).aspx) 上的文档说:

SEM_FAILCRITICALERRORS:
系统不显示严重错误处理程序消息框。相反,系统将错误发送给调用进程。

SEM_NOGPFAULTERRORBOX:
系统不显示 Windows 错误报告对话框。

每个进程都有一个关联的错误模式,向系统指示应用程序将如何响应严重错误。子进程继承其父进程的错误模式。

但是,在调用SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX) 并使用CreateProcessdwCreationFlags = CREATE_NEW_CONSOLE 启动进程后,当子进程失败时,我仍然会收到这些框。

如果重要的话,我使用的确切 Python 代码是:

import ctypes
# 3 is SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX
ctypes.windll.kernel32.SetErrorMode(3)

我该如何解决?

【问题讨论】:

    标签: python winapi testing


    【解决方案1】:

    问题实际上是 Watson 博士(链接已编辑),他粗鲁地忽略了 SetErrorMode(链接已编辑)。阻止沃森博士偷走你的快乐的唯一方法是阻止他接到电话。有两种方法可以做到这一点。

    1. 致电SetUnhandledExceptionHandler(yourexceptionhandler);

      如果您在此处理程序中调用 exit,程序将正常终止并且永远不会调用 Dr. Watson。

      UnhandledExceptionFilter(LPEXCEPTION_POINTERS ep) {
        fputs("Application crashed with unhandled exception!\n", stderr);
      
        // Exit to prevent anything else from handling this exception.
        _exit(-3);
      }
      
      int main() {
        SetUnhandledExceptionFilter(UnhandledExceptionFilter);
      }
      

      这只有在您可以访问源代码并想修改它时才有效。在我的情况下,我可以访问源代码,但它是几百个单独文件的集合,因此在所有文件中添加此代码是不可行的。它也不会处理 main 之前的错误情况,或者只是简单的无效可执行文件。

    2. 使用CreateProcess(..., DEBUG_PROCESS, ...)(link redacted) 和WaitForDebugEvent(link redacted) 在调试器下运行进程

      当运行这样的进程时,所有异常都会传播到调试器,因此它们可以得到适当的处理。

      对于本应简单的问题,这是一个相当复杂的解决方案,但这是我找到的唯一完全阻止 Watson 博士的方法。我目前正在编写一个最小的程序,它试图以各种方式正常运行子进程,除了捕获未处理的异常。提交后我会在此处发布链接。

    【讨论】:

      【解决方案2】:

      错误模式通常被子进程继承。它听起来就像system(或execv,或任何用于产生子进程的东西)的实现在调用CreateProcess 时传递了CREATE_DEFAULT_ERROR_MODE 标志。要获得您想要的行为(继承您设置的错误模式),您必须修改库实现,以便用于生成进程的任何内容都不会传递该标志,或者实现(并使用) 没有通过的新事物。

      【讨论】:

      • CreateProcess 仅被 CREATE_NEW_CONSOLE 调用。
      猜你喜欢
      • 2011-07-01
      • 1970-01-01
      • 2019-03-13
      • 2019-06-10
      • 1970-01-01
      • 2012-09-05
      • 2011-02-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多