Python subprocess : in which case a segfault program returns -11 or 139?

Viewed 1064

I'm using Python 3.7 and subprocess library.

I have a binary my_prog which crashes with segfault :

$> ./my_prog
[1]    9328 segmentation fault  ./my_prog

In my script main.py, I have these lines of code :

try:
    output = subprocess.check_output(['./my_prog'], shell=True, stderr=subprocess.STDOUT)
except subprocess.CalledProcessError as exc:
    print(exc.returncode)
    print(exc.output)

In this case, I get

$> python3 main.py
-11
b''

Ok, subprocess catches the signal SIGSEGV.
Ok, no output. Why not.

But, if I want the same program to read on stdin, I have to modify my line in main.py (the file "text.txt" exists):

output = subprocess.check_output(['./my_prog < text.txt'], shell=True, stderr=subprocess.STDOUT)

And in this case I get :

$> python3 main.py
139
b'/bin/sh: line 1: 17235 Segmentation fault: 11  ./my_prog < text.txt\n'

I know it's 11 + 128, that means SIGSEGV too.
And, now, I have an output !

Even if 139 and -11 mean the same, why the returncode changes in these 2 different situations ? And why is there no output in the first case ?

Thanks :)

EDIT :
Add the difference on output issue.

1 Answers

For efficiency, the shell merely execs the last (or only) command it’s running in certain cases. Then the command is the same process as the shell—the direct child of your Python script—and reports signals in the usual fashion (entirely as the -11).

Redirecting input prevents this, perhaps to avoid issues with prematurely closing all file descriptors open on a terminal. Then the segfault from my_prog is reported to the shell: as if with a -11, but that’s actually a Python convention. The shell prints a message (note that /bin/sh appears in it) and converts that report into an exit status of 139.

It could re-present the signal, in the cases where it doesn’t exec, by killing itself with the same signal (strace does this), but it doesn’t bother with that extra check. (And this way you needn’t wonder whether the shell itself crashed.) It’s unfortunate that shells further restrict the range of usable exit statuses this way, but it’s long established.

Related