I need to write a C++ code which accepts a certain input and prints the respective output. This code is meant to be run using the Python subprocess module. Regardless of inputs and outputs, I need to make sure that the Python code does not terminate prematurely due to runtime errors the C++ code encounters. The basic nature of the C++ code is as follows
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.
}
The Python code which runs it, is as follows:
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"
This is the issue. Even though the C++ code experiences a segmentation fault, the signal handler is invoked, the RuntimeError
is raised, but the returncode of the Popen object is none
, indicating that the process still lives.
Now if the following change is made to the except block:
a.wait()
print a.returncode
if a.returncode == -11:
print "Segmentation Fault Occurred"
The issue is resolved. The output shows that the returncode of the Popen object is -11 and "Segmentation Fault Occurred" is printed to the screen.
The exact same happens if I try to simulate a floating point exception due to divide-by-zero.
Why does this happen?
From the documentation
Popen.wait() Wait for child process to terminate. Set and return returncode attribute.
So returncode
is not set until wait
is called.
Alternately you could perform a non-blocking check to see if process is terminated using poll
, which would set returncode
as well if terminated.
Popen.poll() Check if child process has terminated. Set and return returncode attribute.
note that you don't really need the signal
call (not sure if it's portable on Windows). The code could be simplified like this:
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")
note that you have to a.stdin.flush()
to be sure the input reaches the c++ program.