classification
Title: sys.exit(code) returns "success" to the OS for some nonzero values of code
Type: behavior Stage:
Components: Interpreter Core Versions: Python 3.10, Python 3.9, Python 3.8
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: Arfrever, belopolsky, eryksun, martin.panter, r.david.murray, serhiy.storchaka, skrah, steven.daprano
Priority: normal Keywords:

Created on 2015-04-24 15:29 by belopolsky, last changed 2021-03-12 17:42 by eryksun.

Messages (14)
msg241946 - (view) Author: Alexander Belopolsky (belopolsky) * (Python committer) Date: 2015-04-24 15:29
$ python3
Python 3.4.3 (default, Mar  2 2015, 11:08:35)
[GCC 4.4.7 20120313 (Red Hat 4.4.7-4)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> import subprocess
>>> subprocess.call([sys.executable, '-c', "import sys;sys.exit(512)"])
0
>>> subprocess.call([sys.executable, '-c', "import sys;sys.exit(256)"])
0

See also #14376.
msg241952 - (view) Author: Stefan Krah (skrah) * (Python committer) Date: 2015-04-24 16:07
At first glance the return values look right to me:

The value of exit returned to the parent should be status & 0377.
msg241954 - (view) Author: Alexander Belopolsky (belopolsky) * (Python committer) Date: 2015-04-24 16:43
> The value of exit returned to the parent should be status & 0377.

Apparently, this is not so on Windows.  See msg241903 in #24045.

POSIX defines [1] exit to return status & 0377, but that does not mean that sys.exit(256) must return 0 without a warning.  It is very unlikely that someone would intentionally use code=256 to signify success.  It is much more likely that sys.exit(256) is a result of a programming error.

I believe a better behavior for sys.exit() would be to truncate the code values to 8-bit range so that non-zero status would always be returned as non-zero, but possibly different value.

[1] http://pubs.opengroup.org/onlinepubs/009695399/functions/exit.html
msg241957 - (view) Author: Ethan Furman (ethan.furman) * (Python committer) Date: 2015-04-24 16:57
If anything changes here it needs to be O/S dependent.  MS Windows can work with DWORD return values, so truncating to 8-bits is wrong for that platform.
msg241958 - (view) Author: Eryk Sun (eryksun) * (Python triager) Date: 2015-04-24 17:09
> I believe a better behavior for sys.exit() would be to truncate 
> the code values to 8-bit range so that non-zero status would 
> always be returned as non-zero, but possibly different value.

OK, so long as it's just for POSIX systems. Windows ExitProcess, ExitThread, TerminateProcess, and TerminateThread all use an unsigned int value for the exit code, and it's common to use a [Win32 error code][1] in the 16-bit range 0x0000 to 0xFFFF.

[1]: https://msdn.microsoft.com/en-us/library/cc231199
msg241961 - (view) Author: Alexander Belopolsky (belopolsky) * (Python committer) Date: 2015-04-24 17:24
I agree that the truncation limits should be OS dependent and preserve the values to the extent possible on a given platform.  I just want to avoid a situation when sys.exit(code) returns zero for a non-zero code.

BTW, what does sys.exit(2**63) return on Windows?
msg241964 - (view) Author: Ethan Furman (ethan.furman) * (Python committer) Date: 2015-04-24 17:45
Windows 7

C:\Python27>python
Python 2.7.5 (default, May 15 2013, 22:43:36) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
--> import sys
--> sys.exit(2**63)
9223372036854775808

C:\Python27>python
Python 2.7.5 (default, May 15 2013, 22:43:36) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
--> import sys
--> sys.exit(2**63+1)
9223372036854775809
msg241965 - (view) Author: Alexander Belopolsky (belopolsky) * (Python committer) Date: 2015-04-24 17:53
--> sys.exit(2**63)
9223372036854775808

Interesting.  So it is probably not unheard of in the Windows world to use errors codes like 1000,1001,..1024,.. to avoid conflicts with "system" codes.

Maybe on POSIX systems, sys.code(code) should print code and return say 255 for code outside of -255..255 range?
msg241967 - (view) Author: Eryk Sun (eryksun) * (Python triager) Date: 2015-04-24 18:18
> --> import sys
> --> sys.exit(2**63)
> 9223372036854775808

The above is only Python 2.x behavior. On Windows, sys.maxint is 2147483647 (even for 64-bit Windows), so 2**63 is a Python long. Thus handle_system_exit takes the PyFile_WriteObject branch, with the actual exit code set to 1.

    >>> import sys
    >>> sys.exit(2**63)
    9223372036854775808    
    C:\>echo %errorlevel%
    1

In Python 3, PyLong_AsLong overflows for any value bigger than LONG_MAX, which sets the result to -1, i.e. 32-bit 0xFFFFFFFF, with  overflow set. handle_system_exit ignores the overflow exception, so any exit code larger than 0x7FFFFFFF (2**31-1) is returned as 0xFFFFFFFF (2**32-1).

    >>> cmd = '%s -c "import sys;sys.exit(%%d)"' % sys.executable
    >>> subprocess.call(cmd % (2**31-1))                         
    2147483647
    >>> subprocess.call(cmd % (2**31))                           
    4294967295
    >>> subprocess.call(cmd % (2**63))
    4294967295
msg242272 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2015-04-30 14:59
Printing the actual value feels more consistent with the documented API, so I'm in favor of that (ie: don't let errors pass silently).  I'm sure someone somewhere is depending on this :(, but I see you have versions marked for 3.5 only, which makes sense to me.
msg242359 - (view) Author: Steven D'Aprano (steven.daprano) * (Python committer) Date: 2015-05-02 00:13
Maybe I've misunderstood RDM's comment, but if sys.exit(code) starts automatically printing the return code, that's going to break a lot of scripts.
msg242367 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2015-05-02 01:57
I meant when it is otherwise out of range.  That is, treat it like any other object that can't be returned as the return code: print it.  But only if it can't otherwise be used as the exit code.
msg242375 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2015-05-02 04:42
Python 2 prints large return code only by accident, because it have unsupported type (sys.exit supports only int, not long). This is considered as a bug (issue14376) because small return codes of type long (0L or 1L) are printed too.

I don't think this issue need other fix besides a note that the program can return "success" for some non-zero values.
msg273848 - (view) Author: Martin Panter (martin.panter) * (Python committer) Date: 2016-08-29 01:54
Here is a relevant Posix bug thread:
http://austingroupbugs.net/view.php?id=947

As well as Windows, apparently Solaris, OS X, and a recent version of Free BSD have more than eight bits of exit status. I don’t know if Python’s sys.exit() supports this though.
History
Date User Action Args
2021-03-12 17:42:44eryksunsetversions: + Python 3.8, Python 3.9, Python 3.10, - Python 3.5
2016-08-29 01:54:15martin.pantersetnosy: + martin.panter
messages: + msg273848
2015-07-21 07:15:43ethan.furmansetnosy: - ethan.furman
2015-05-03 05:55:53Arfreversetnosy: + Arfrever
2015-05-02 04:42:21serhiy.storchakasetnosy: + serhiy.storchaka
messages: + msg242375
2015-05-02 01:57:25r.david.murraysetmessages: + msg242367
2015-05-02 00:13:52steven.dapranosetnosy: + steven.daprano
messages: + msg242359
2015-04-30 14:59:12r.david.murraysetnosy: + r.david.murray
messages: + msg242272
2015-04-24 18:18:52eryksunsetmessages: + msg241967
2015-04-24 17:53:43belopolskysetmessages: + msg241965
2015-04-24 17:45:42ethan.furmansetmessages: + msg241964
2015-04-24 17:24:39belopolskysetmessages: + msg241961
2015-04-24 17:09:33eryksunsetnosy: + eryksun
messages: + msg241958
2015-04-24 16:57:16ethan.furmansetnosy: + ethan.furman
messages: + msg241957
2015-04-24 16:51:45belopolskysettitle: sys.exit(code) returns "success" to the OS for some values of code -> sys.exit(code) returns "success" to the OS for some nonzero values of code
2015-04-24 16:43:21belopolskysetmessages: + msg241954
2015-04-24 16:07:25skrahsetnosy: + skrah
messages: + msg241952
2015-04-24 15:29:13belopolskycreate