gpt4 book ai didi

python - 如何检查子进程是否在Windows上被信号杀死

转载 作者:可可西里 更新时间:2023-11-01 10:31:47 32 4
gpt4 key购买 nike

问题

给定一个从python开始的子流程,其代码类似于:

import subprocess
p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
p.communicate()
print('Return code: {}'.format(p.returncode))

根据 official documentation,可以检查子进程是否被信号终止:

A negative value -N indicates that the child was terminated by signal N (POSIX only).



但仅在POSIX平台上。

有没有办法检查Windows平台上的进程是否被信号终止(不在乎哪个信号)?

背景

我在运行googletest测试时遇到了这个问题。 break-on-failure CLI flag test在Windows平台(VC14,VS2017)上失败,但在POSIX平台(2x Ubuntu,2x macOS)上运行良好。

在命令行上手动获得以下结果:
> .\googletest-break-on-failure-unittest_.exe --gtest_break_on_failure
[==========] Running 1 test from 1 test case.
[----------] Global test environment set-up.
[----------] 1 test from Foo
[ RUN ] Foo.Bar
<some path>\googletest\test\googletest-break-on-failure-unittest_.cc(52): error: Expected equality of these values:
2
3

> echo %ERRORLEVEL%
-2147483645

但是,调用此测试的python包装器会接收 2147483651(正数)。

(我只是在 this line之前添加了打印件)

请注意,这些引用以十六进制表示的数字 0xFFFFFFFF80000003(负数)和 0x‭80000003‬(正数),并且未对返回码进行进一步处理。 (请参阅 here)

为什么会这样更改返回码?

PS:是的,我已经检查了 GTEST_OS_WINDOWSGTEST_HAS_SEH在C++代码中是否正确。

最佳答案

CMD的ERRORLEVEL环境变量是一个32位带符号的值。正范围是0x00000000-0x7FFFFFFF(0直到2147483647),负范围是0x80000000-0xFFFFFFFF(-2147483648直到-1)。当进程由于未处理的异常而退出时,状态通常是异常代码,通常是32位带符号的 NTSTATUS 值。也就是说,没有什么可以阻止我们使用超过0x7FFFFFFF的无符号退出代码来调用ExitProcessTerminateProcess,因此CMD中的ERRORLEVEL负值本身并不意味着进程异常退出。

在这种情况下,-2147483645是NTSTATUS代码STATUS_BREAKPOINT(0x80000003)。这源自Google Test的 gtest_break_on_failure 选项,该选项调用WinAPI DebugBreak 。对于x86体系结构,后一个函数仅执行int 3指令(软件中断3),该指令被困在内核中以引发断点异常。

通常,在没有附加调试器的情况下,这将执行默认的Windows未处理异常处理程序,该处理程序将调用Windows Error Reporting(请参见下文)。但是问题中链接的代码将ExitWithExceptionCode设置为应用程序的未处理异常过滤器。该过滤器仅通过exit(exception_pointers->ExceptionRecord->ExceptionCode)退出。

至于Unix信号,Windows内核没有实现它们。 C运行时实现了标准C所需的六个。在控制台应用程序中,标准SIGINT信号与控制台的CTRL_C_EVENT关联。非标准SIGBREAK信号用于其他控制台控制事件,包括CTRL_BREAK_EVENTCTRL_CLOSE_EVENT。这些事件的默认处理程序称为ExitProcess(STATUS_CONTROL_C_EXIT)。因此,要从字面上回答问题,以确定进程是否被控制台“信号”杀死,请检查STATUS_CONTROL_C_EXIT(0xC000013A或-1073741510)。

处理未处理的异常

  • 如果将调试器连接到进程调试端口,则内核会向其发送优先机会异常事件。如果它不处理异常,则内核将异常分配到线程的向量异常处理程序和结构化异常处理程序链(基于堆栈,与当前帧相反检查)中。我们将假定异常未由任何一个处理。
  • 最后检查的框架是线程启动功能RtlUserThreadStart的框架。此帧的处理程序_C_specific_handler传递了一个调度记录,使它可以确定范围的异常过滤器。给定先前通过RtlSetUnhandledExceptionFilter设置的过滤器,该过滤器又调用该进程的未处理异常过滤器。在进程启动时,kernelbase.dll的初始化例程将其设置为适当命名的函数UnhandledExceptionFilter
  • 如果连接了调试器,则UnhandledExceptionFilter返回EXCEPTION_CONTINUE_SEARCH。随后,内核向调试器发送第二次异常事件。如果调试器不处理该异常,则内核尝试将事件发送到子系统,即Windows session 服务器csrss.exe。服务器继而将故障中继到Windows错误报告(WER)服务,该服务最终将终止该过程。
  • 如果未附加调试器,则UnhandledExceptionFilter调用应用程序的未处理异常过滤器(如果先前是通过 SetUnhandledExceptionFilter 设置的)。如果应用程序过滤器返回EXCEPTION_CONTINUE_EXECUTIONEXCEPTION_EXECUTE_HANDLER,则UnhandledExceptionFilter将此值返回到帧处理程序。
  • 如果应用程序尚未设置自己的过滤器,或者其过滤器返回EXCEPTION_CONTINUE_SEARCH,则UnhandledExceptionFilter接下来检查作业SEM_NOGPFAULTERRORBOX的作业,进程和线程错误模式。此标志禁用错误报告,在这种情况下,过滤器仅返回EXCEPTION_EXECUTE_HANDLER
  • 如果允许错误报告,则在Windows错误报告(WER)服务上调用UnhandledExceptionFilter。 WER处于循环状态,其行为最终取决于注册表中的配置方式,组策略以及当前Windows版本的默认行为。 WER可以基于系统“AeDebug”设置创建并附加调试器过程。如果它附加了调试器,UnhandledExceptionFilter将返回EXCEPTION_CONTINUE_SEARCH,就像已经附加了调试器一样。否则,它返回EXCEPTION_EXECUTE_HANDLER
  • 最终,如果它为“未处理的”异常执行异常处理程序,则首先通过RtlUserThreadStart将栈解卷到RtlUnwindEx框架,该框架将调用中间框架中的所有finally终止处理程序。异常处理程序的执行上下文通过RtlRestoreContext恢复,并且异常代码在整数返回寄存器中设置(例如x64中的rax)。最后,处理程序通过NtTerminateProcess(NtCurrentProcess(), exceptionCode)自终止。
  • 关于python - 如何检查子进程是否在Windows上被信号杀死,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54182993/

    32 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com