【问题标题】:detect program termination (C, Windows)检测程序终止(C、Windows)
【发布时间】:2010-11-26 12:38:03
【问题描述】:

我有一个程序必须在完成之前执行某些任务。问题是有时程序会因异常而崩溃(例如无法访问数据库等)。 现在,有什么方法可以检测异常终止并在它死之前执行一些代码?

谢谢。

代码表示赞赏。

【问题讨论】:

  • 使用 SIGSEGV 信号处理程序。 ;-)

标签: c windows process termination


【解决方案1】:

几年前,我在 ddj.com 上发表了一篇关于“事后调试”的文章。

它包括用于检测异常终止的 windows 和 unix/linux 的源代码。不过,根据我的经验,使用 SetUnhandledExceptionFilter 安装的 Windows 处理程序并不总是被调用。在许多情况下,它被调用,但我从客户那里收到不少日志文件,其中不包括来自已安装处理程序的报告,即访问违规是原因。

http://www.ddj.com/development-tools/185300443

【讨论】:

    【解决方案2】:

    sysinternals forum threads 关于通过挂钩 NT Internals 来防止终端进程尝试,但您真正想要的是看门狗或对等进程(合理的方法)或某种拦截灾难性事件的方法(相当冒险)。

    编辑:它们使这变得困难是有原因的,但是可以拦截或阻止杀死您的进程的尝试。我知道你只是想在退出前清理一下,但是一旦有人释放了一个不能立即杀死的进程,就会有人要求立即杀死它的方法,以此类推。无论如何,要走这条路,请参阅上面的链接线程并搜索您在其中找到的一些关键字以获取更多信息。 hook OR filter NtTerminateProcess 等等。我们在这里讨论内核代码、设备驱动程序、防病毒、安全、恶意软件、rootkit 的东西。在这方面有帮助的一些书籍是Windows NT/2000 Native APIUndocumented Windows 2000 Secrets: A Programmer's CookbookRootkits: Subverting the Windows Kernel,当然还有Windows® Internals: Fifth Edition。这些东西编写起来并不难,但要恰到好处却很棘手,而且您可能会引入意想不到的副作用。

    也许Application Recovery and Restart Functions 有用吗?受 Vista 和 Server 2008 及更高版本支持。

    ApplicationRecoveryCallback 回调函数 应用程序定义的回调函数,用于在应用程序遇到未处理的异常或无响应时保存数据和应用程序状态信息。

    在使用 SetUnhandledExceptionFilter 时,MSDN Social discussion 建议要使这项工作可靠,在内存中修补该方法是确保调用过滤器的唯一方法。建议改为使用 __try/__except 进行包装。不管怎样,文章"SetUnhandledExceptionFilter" and VC8 中有一些示例代码和过滤调用 SetUnhandledExceptionFilter 的讨论。

    另外,有关 AddVectoredExceptionHandler 的一些示例代码,请参阅 The Awesome Factor 的 Windows SEH Revisited

    【讨论】:

    • 谢谢。我以前看过那些。有2个问题,寿。 1)我必须支持XP。 2)我不需要从崩溃中恢复。我只需要在关闭应用程序之前(优雅地或崩溃之前)保存一些文件并关闭数据库连接。
    • 明白了。添加了一些信息和链接到示例代码和 SUEF 和 AVEH 的讨论。
    • 让我试试这个。尽管如此,我还是无法捕捉到 TerminateProcess。据我所知,这是不可能的
    • 我相信这是可能的,只是需要做很多工作。在内核级别,您几乎可以做任何事情,挂钩和修补大多数事情。搜索“hook nterminateprocess”等。我将稍微扩展我的第一段,但请记住,它们使事情变得困难,因为他们不想要军备竞赛。 IE。有人会问的下一个问题是“我如何杀死拒绝立即终止的错误进程?”我们在设备驱动程序、防病毒、rootkit 领域。
    • :) 没想到你是。其他方法,如 SUEF、AVEH、信号处理程序、看门狗 proc 或 __try/__except 是否适用于您需要的所有情况?如果是这样,那么这就是要走的路(请报告什么对你有用——这是一个有趣的话题)。如果您需要更多,您将不得不使用一些非典型技术。
    【解决方案3】:

    1. Win32

    Win32 API 包含一种通过SetUnhandledExceptionFilter 函数执行此操作的方法,如下所示:

    LONG myFunc(LPEXCEPTION_POINTERS p)
    {
         printf("Exception!!!\n");     
         return EXCEPTION_EXECUTE_HANDLER;
    }
    
    int main()
    {
         SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)&myFunc);    
         // generate an exception !
         int x = 0;
         int y = 1/x;
         return 0;
    }
    

    2。 POSIX/Linux

    我通常通过signal() 函数执行此操作,然后适当地处理 SIGSEGV 信号。您还可以处理 SIGTERM 信号和 SIGINT,但不能处理 SIGKILL(按设计)。您可以使用strace() 进行回溯以查看导致信号的原因。

    【讨论】:

    • 另外,关于您对 TerminateProcess() 的评论...简单的答案是,在为您的流程调用 TerminateProcess() 之后,您无法做任何事情。不要过关,不要收取 200 美元。您的进程现在退出。时期。结束。
    • 感谢 cmets。问题也不例外。问题是检测到崩溃或终止呼叫。我已经可以处理的异常
    • 这就是 SetUnhandledExceptionFilter 的作用,它处理“崩溃”,如堆栈溢出、空内存访问等。它不仅仅是 try/catch 意义上的异常处理程序。
    • 参见 msdn.microsoft.com/en-us/library/aa363082(VS.85).aspx,它描述了 SEH 可以处理的所有“崩溃”。
    • 另外,我认为函数名称让你感到困惑。此函数专门用于处理您所称的“异常终止”。换句话说,这是在您的代码崩溃时调用的函数。不过,它可以也不会处理 TerminateProcess。因此,正如 Piotr 所指出的,如果您的进程通过 TerminateProcess 终止,它不会“触发”,这是设计使然。 SEH 被无数程序用来在发生崩溃时“打电话回家”。
    【解决方案4】:

    这取决于您如何处理“例外”。如果您正确处理它们并退出程序,则可以使用atexit() 注册要在退出时调用的函数。

    在真正异常终止的情况下不起作用,例如segfault。

    不了解 Windows,但在兼容 POSIX 的操作系统上,您可以安装信号处理程序,该处理程序将捕获不同的信号并对其进行处理。当然你抓不到SIGKILLSIGSTOP

    自 C89 以来,信号 API 是 ANSI C 的一部分,因此 Windows 可能支持它。有关详细信息,请参阅signal() 系统调用。

    【讨论】:

    • 我正在使用类似的东西来捕获 ctrl-c 和其他终止信号,但我无法捕获 TerminateProcess。如果我没记错的话,你不能停止 SIGKILL,这同样适用于 TerminateProcess。它只会导致应用死机。
    【解决方案5】:

    首先,尽管这很明显:您永远不可能有一个完全可靠的解决方案——有人总是可以通过敲击电源线来终止您的进程。所以你需要妥协,并且你需要仔细列出妥协的细节。

    其中一个更强大的解决方案是将相关代码放入包装程序中。包装程序调用你的“真实”程序,等待它的进程终止,然后——除非你的“真实”程序明确表示它已经正常完成——运行清理代码。这对于测试工具之类的事情相当普遍,因为测试程序可能会崩溃或中止或以其他方式以意想不到的方式死亡。

    如果有人在你的包装函数上执行 TerminateProcess 会发生什么,这仍然会给你带来困难,如果这是你需要担心的事情。如有必要,您可以通过在 Windows 中将其设置为服务并使用操作系统的功能在其死机时重新启动它来解决此问题。 (这只是稍微改变了一些事情;仍然有人可以停止服务。)此时,您可能正处于需要通过诸如创建文件之类的持久性事物来表示成功完成的地步。

    【讨论】:

    • 我同意你的看法。我的主要问题是在 TerminateProcess 或其他不可预见的事件中死亡之前执行最后一个操作。其余的事件被处理。我与项目负责人谈过将监控应用程序转换为服务的问题,但没有。我想没有办法做到这一点......
    【解决方案6】:

    对不起,不是 Windows 程序员。但也许

    _onexit()
    

    注册一个在程序终止时调用的函数。

    http://msdn.microsoft.com/en-us/library/aa298513%28VS.60%29.aspx

    【讨论】:

    • 谢谢,但它并没有真正帮助。我可以正常终止。
    【解决方案7】:

    如果它仅适用于 Windows,那么您可以使用 SEH (SetUnhandledExceptionFilter) 或 VEH (AddVectoredExceptionHandler,但它仅适用于 XP/2003 及更高版本)

    【讨论】:

    • 我认为这可能会有所帮助。有样品 sn-p 吗?
    • codepad.org/mUAUB25D - 但这是最​​简单的一种,网络上有更复杂的崩溃处理程序(例如在 CodeProject 上)。
    • 我试过了,它看起来不错,但是如果我杀死了进程(从任务管理器等),它不会检测到它。
    • 来自 MSDN:“如果一个进程被 TerminateProcess 终止,则该进程的所有线程都会立即终止,没有机会运行其他代码。这意味着线程不会执行终止处理程序块中的代码。此外,不会通知附加的 DLL 进程正在分离。"。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-13
    • 2010-11-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多