[issue24045] Behavior of large returncodes (sys.exit(nn))
New submission from Ethan Furman: Not sure if this is a bug, or just One of Those Things: sys.exit(large_value) can wrap around if the value is too large, but this is O/S dependent. linux (ubuntu 14.04) $ python Python 2.7.8 (default, Oct 20 2014, 15:05:29) [GCC 4.9.1] on linux2 Type "help", "copyright", "credits" or "license" for more information. --> import sys --> sys.exit(256) $ echo $? 0 $ python Python 2.7.8 (default, Oct 20 2014, 15:05:29) [GCC 4.9.1] on linux2 Type "help", "copyright", "credits" or "license" for more information. --> import sys --> sys.exit(257) $ echo $? 1 M$ (Windows 7)
python Python 2.7... --> import sys --> sys.exit(65535) echo %errorlevel% 65535
python Python 2.7... --> import sys --> sys.exit(100000) echo %errorlevel% 100000
Perhaps a minor doc update that talks about return codes and why they might not be exactly what was given to Python?
----------
assignee: docs@python
messages: 241903
nosy: docs@python, ethan.furman
priority: normal
severity: normal
status: open
title: Behavior of large returncodes (sys.exit(nn))
versions: Python 2.7, Python 3.5
_______________________________________
Python tracker
Changes by Arfrever Frehtes Taifersar Arahesis
Changes by Ethan Furman
Martin Panter added the comment:
Is this a duplicate of Issue 24052?
----------
nosy: +martin.panter
_______________________________________
Python tracker
Eryk Sun added the comment:
Unix waitpid() packs the process exit status and terminating signal number into a single status value. As specified by POSIX [1], the WEXITSTATUS function returns only the lower 8 bits of the process exit status. In theory, waitid() and wait6() can return the full 32-bit status value in the siginfo_t si_status. Apparently NetBSD does this [2], but evidently Linux does not:
>>> p = subprocess.Popen(['python3', '-c','import os; os._exit(257)'])
>>> os.waitid(os.P_PID, p.pid, os.WEXITED).si_status
1
For Windows, programs sometimes return 16-bit WinAPI error codes or 32-bit HRESULT error codes. A critical error or unhandled exception may even result in returning a 32-bit NTSTATUS code (e.g. if you cancel the Windows error reporting dialog).
Currently the Python 3 implementation of sys.exit and os._exit converts to a signed long, but the Windows exit code is an unsigned long. To use integer return codes in the range 0x80000000-0xFFFFFFFF requires manually converting to the corresponding negative signed value.
Technically the two error types that require 32-bit values are signed (i.e. HRESULT and NTSTATUS), so this shouldn't be a problem. However, in practice sometimes a function -- and definitely subprocess.Popen -- returns an HRESULT error code as an unsigned value.
It would be convenient, at least on Windows, if handle_system_exit in Python/pythonrun.c converted the value using PyLong_AsUnsignedLongMask instead of PyLong_AsLong. Similarly os._exit could use Argument Clinic's "unsigned int" format, which also calls PyLong_AsUnsignedLongMask.
The problem with using PyLong_AsLong on Windows (32-bit or 64-bit) is that it overflows with an error value of -1 for values greater than 0x7FFFFFFF. In this case, os._exit raises OverflowError. handle_system_exit, on the other hand, ignores the exception. It just uses the -1 error value as the exit code, i.e. 0xFFFFFFFF.
[1]: http://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html
[2]: https://www.daemon-systems.org/man/wait.2.html
----------
nosy: +eryksun
_______________________________________
Python tracker
Eryk Sun
participants (4)
-
Arfrever Frehtes Taifersar Arahesis
-
Eryk Sun
-
Ethan Furman
-
Martin Panter