Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Exit status of $? using python when segmentation fault occured

I need to execute echo $? using python3 and capture the exit status. I need this especially for capturing the Segmentation fault (core dumped) status. I tried :

>>> os.system('echo $?')
0
0

got 0 0. Also, for segfault,

>>> os.system('./a.out')
Segmentation fault (core dumped)
35584

After above command, I again got:

>>> os.system('echo $?')
0
0

Also, why is 0 getting printed twice? I went through the doccumentation of python-3 which says:

os.system(command)

On Unix, the return value is the exit status of the process encoded in the format specified for wait(). Note that POSIX does not specify the meaning of the return value of the C system() function, so the return value of the Python function is system-dependent.

Does this something say about such behavior? Help me clarify on this.

Note: I already ran the ulimit -c unlimited before all above steps. The expected result should be non-zero or 139(to be specific).

Edit: I am thinking if there is a limitation on this!

Thanks!

like image 673
Dr. Essen Avatar asked Oct 20 '25 05:10

Dr. Essen


2 Answers

No, you don't need to execute echo $?. It wouldn't be useful. The exit status of the program is the return value of the function os.system. That's what the number 35584 is. The documentation os os.system tells you to read the documentation of os.wait which explains

a 16-bit number, whose low byte is the signal number that killed the process, and whose high byte is the exit status (if the signal number is zero); the high bit of the low byte is set if a core file was produced.

However, note that depending on the shell, with os.system('./a.out'), you may be getting the exit status of a.out or the exit status of the shell itself. Normally there's no difference, because the exit status of the shell is the exit status of the last command it executes. But if the command dies from a signal, then there is a difference. The shell won't kill itself with the same signal, it will return a status that encodes the signal. In most shells, that's 128 + signal_number. For example, if the program dies of signal 11 (segfault on Linux) and leaves a core dump, then its status as returned by wait is 11. But if there's a shell in between, then the shell will exit normally with the exit code 128+11. That's what you're seeing: 35584 is (128 + 11) << 8.

To avoid this complication, use subprocess.call or one of its variants (you can use subprocess.run if you don't need your code to run Python <=3.4).

returncode = subprocess.call(['./a.out'], shell=False).returncode
if returncode & 0xff == 0:
    exit_code = returncode >> 8
    print('The program exited normally with status {}.'.format(exit_code))
else:
    print('The program was killed by signal {}.'.format(returncode))

If you run os.system('echo $?'), this starts a new shell. You're printing the initial value of $? in that shell, before it has run any command, and the initial value of $? in a shell is 0.

You see 0 twice in the interactive environment because the first one is the one printed by the echo command and the second one is the value of the Python expression. Compare os.system('echo hello').

Note that with os.system, you can't access the output of the command, so if you print something with echo, you can't use it in the program. You'd have to use functions in the subprocess module for that, but you need this only if you need the output of ./a.out, not to get its exit status.

like image 109
Gilles 'SO- stop being evil' Avatar answered Oct 22 '25 19:10

Gilles 'SO- stop being evil'


When running:

>>> os.system('echo $?')
0
0

and if your previous command was successful a first 0 will be print by echo $? and another one will be the return code of the call to echo $? that has just succeeded so you will have another 0 printed.

The return code of the script/command that you execute will directly be returned to your python program by os.system function so you do not need to use echo $?

Examples:

$ more return_code*
::::::::::::::
return_code1.py
::::::::::::::
import os

print os.system('sleep 1')
#will print 0 after 1sec
::::::::::::::
return_code2.py
::::::::::::::
import os

print os.system('ls abcdef')
#will print a rc!=0 if the file abcdef is not present in your working directory

Executions:

$ python return_code1.py 
0

and

$ python return_code2.py                                                                                                                                                                                                                                        
ls: cannot access 'abcdef': No such file or directory
512
like image 29
Allan Avatar answered Oct 22 '25 18:10

Allan



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!