为什么由于分段错误而导致的子进程被立即杀死?

时间:2016-12-25 12:41:22

标签: python-2.7 subprocess signals sigsegv sigchld

我需要编写一个C ++代码,它接受某个输入并打印相应的输出。此代码旨在使用Python子进程模块运行。无论输入和输出如何,我都需要确保Python代码不会因C ++代码遇到的运行时错误而过早终止。 C ++代码的基本特性如下

int main()
{
  /*The pointer is initialized to NULL to simulate a segmentation fault
    Also the n is meant for simulating input.*/
  int *p=NULL,n;   
  cin>>n;
  cout<<*p<<endl;  //This causes a segmentation fault.
}

运行它的Python代码如下:

from subprocess import *
from signal import *

def handler(signum,frame):
    raise RuntimeError("Runtime Error")

call(["g++","try.cpp"])
a = Popen(["stdbuf","-i0","-o0","-e0","./a.out"],stdin = PIPE,stdout = PIPE)
try:
    #Handler for signal due to termination of child process
    signal(SIGCHLD,handler)    
    a.stdin.write("1\n")
    temp = a.stdout.readline()
except RuntimeError as e:
    print e
    print a.returncode   

#Returncode of process killed due to SIGSEGV is -11
    if a.returncode == -11:   
        print "Segmentation Fault Occurred"

这就是问题所在。即使C ++代码遇到分段错误,也会调用信号处理程序,引发RuntimeError,但Popen对象的返回码为none,表示进程仍然存在。
现在,如果对except块进行了以下更改:

a.wait()
print a.returncode        
if a.returncode == -11:   
    print "Segmentation Fault Occurred"

问题已解决。输出显示Popen对象的返回码为-11,并且“分段故障发生”显示在屏幕上。
如果我尝试模拟由于被零除的浮点异常,则会发生相同的情况 为什么会这样?

1 个答案:

答案 0 :(得分:1)

来自文档

  

Popen.wait()      等待子进程终止。设置并返回returncode属性。

因此,在调用returncode之前,wait不会设置。

或者,您可以执行非阻止检查以查看是否使用poll终止了流程,如果已终止,也会设置returncode

  

Popen.poll()      检查子进程是否已终止。设置并返回returncode属性。

请注意,您并非真正需要signal电话(不确定它是否可以在Windows上移植)。代码可以简化为:

a = Popen(["stdbuf","-i0","-o0","-e0","./a.out"],stdin = PIPE,stdout = PIPE)
a.stdin.write("1\n")
a.stdin.flush()
temp = a.stdout.readline()
if temp:
    # do something
    print("output "+temp)
else:
    # empty string: recieved process has ended, probably unexpectedly
    # because it should have printed something
    pass

returncode = a.wait()

#Returncode of process killed due to SIGSEGV is -11
if returncode  == -11:   
    print("Segmentation Fault Occurred")

请注意,您必须a.stdin.flush()以确保输入到达c ++程序。