-
-
Notifications
You must be signed in to change notification settings - Fork 32.2k
bpo-40138: Fix Windows os.waitpid() for large exit code #19637
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Fix the Windows implementation of os.waitpid() for exit code larger than "INT_MAX >> 8". The exit status is now interpreted as an unsigned number. os.waitstatus_to_exitcode() now accepts wait status larger than INT_MAX.
@eryksun: Would you mind to review this change? |
On Windows, os.waitpid() truncates the exit status if it's larger than INT_MAX >> 8. I think that Python 3.7 and 3.8 should also be fixed. |
cc @zooba |
Lib/test/test_os.py
Outdated
exitcode = 23 | ||
def check_waitpid(self, code, exitcode, callback=None): | ||
# On Windows, os.spawnv() spawns a shell: run Python with a filename, | ||
# rather than with -c CODE, to avoid the need to quote the code. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
spawnv
concatenates the arguments into a command line that gets passed to CreateProcessW
in the lpCommandLine
parameter. No shell is involved here. Unlike Python's subprocess.list2cmdline
, the CRT's spawn
family does not create a command line according to MSVC rules. It simply concatenates with spaces, which leaves it up to the caller to ensure that each argument is quoted and escaped according to the rules of the target application.
You can avoid the need to escape quotes in an argument by using only single quotes, which have no special meaning in MSVC argv
parsing. For example: args = ['python', '-c', f'"{code}"']
, where code
contains no double quote characters.
There's no need for args[0]
to be a fully-qualified path with spawnv
. Actually, what you're doing by setting args[0] = sys.executable
is wrong. It only works because the test build's path to "python.exe" contains no spaces. If the path has spaces and isn't quoted, then C argv[0]
will only include up to the first space in the path, and the rest will be in argv[1]
, and so on. If you want to use the full path, it has to be quoted. For example, where sys.executable
is "C:\Program Files\Python38\python.exe":
>>> os.spawnv(os.P_WAIT, sys.executable, [f'"{sys.executable}"', '-V'])
Python 3.8.1
0
Failing example without quoting:
>>> os.spawnv(os.P_WAIT, sys.executable, [sys.executable, '-V'])
C:\Program: can't open file 'Files\Python38\python.exe': [Errno 2] No such file or directory
2
Preferably, just use unqualified "python":
>>> os.spawnv(os.P_WAIT, sys.executable, ['python', '-V'])
Python 3.8.1
0
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alright, I didn't think about quoting sys.executable. I fixed the test.
/* shift the status left a byte so this is more like the POSIX waitpid */ | ||
return Py_BuildValue(_Py_PARSE_INTPTR "i", res, status << 8); | ||
return Py_BuildValue(_Py_PARSE_INTPTR "K", res, ustatus << 8); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any possibility that os.waitpid
could simply stop shifting the status value by a byte in Windows? With the introduction of os.waitstatus_to_exitcode
, scripts no longer need to make assumptions about the status value format, and the Windows implementation of waitstatus_to_exitcode
could simply return the status value unchanged.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any possibility that os.waitpid could simply stop shifting the status value by a byte in Windows?
That would be a backward incompatible changes. If you look at changes that I made in https://bugs.python.org/issue40094 to use os.waitstatus_to_exitcode(), you can see that even in the Python stdlib, plently of code used directly "status >> 8" without even checking os.WIFEXITED().
I don't think that it's worth it to change how waitpid() encodes the exit code in the exit status. You should now use os.waitstatus_to_exitcode() to write portable code.
Fix the Windows implementation of os.waitpid() for exit code
larger than "INT_MAX >> 8". The exit status is now interpreted as an
unsigned number.
os.waitstatus_to_exitcode() now accepts wait status larger than
INT_MAX.
https://bugs.python.org/issue40138