mirror of
https://github.com/python/cpython.git
synced 2025-08-31 05:58:33 +00:00
Fixes Issue #16114: The subprocess module no longer provides a
misleading error message stating that args[0] did not exist when either the cwd or executable keyword arguments specified a path that did not exist. It now keeps track of if the child got as far as preexec and reports it if not back to the parent via a special "noexec" error message value in the error pipe so that the cwd can be blamed for a failed chdir instead of the exec of the executable being blamed instead. The executable is also always reported accurately when exec fails. Unittests enhanced to cover these cases.
This commit is contained in:
parent
a256841b4b
commit
5591b02a4c
4 changed files with 63 additions and 9 deletions
|
@ -1169,6 +1169,7 @@ class Popen(object):
|
|||
|
||||
if executable is None:
|
||||
executable = args[0]
|
||||
orig_executable = executable
|
||||
|
||||
# For transferring possible exec failure from child to parent.
|
||||
# Data format: "exception name:hex errno:description"
|
||||
|
@ -1224,6 +1225,7 @@ class Popen(object):
|
|||
self._child_created = True
|
||||
if self.pid == 0:
|
||||
# Child
|
||||
reached_preexec = False
|
||||
try:
|
||||
# Close parent's pipe ends
|
||||
if p2cwrite != -1:
|
||||
|
@ -1288,6 +1290,7 @@ class Popen(object):
|
|||
if start_new_session and hasattr(os, 'setsid'):
|
||||
os.setsid()
|
||||
|
||||
reached_preexec = True
|
||||
if preexec_fn:
|
||||
preexec_fn()
|
||||
|
||||
|
@ -1303,6 +1306,8 @@ class Popen(object):
|
|||
errno_num = exc_value.errno
|
||||
else:
|
||||
errno_num = 0
|
||||
if not reached_preexec:
|
||||
exc_value = "noexec"
|
||||
message = '%s:%x:%s' % (exc_type.__name__,
|
||||
errno_num, exc_value)
|
||||
message = message.encode(errors="surrogatepass")
|
||||
|
@ -1364,10 +1369,17 @@ class Popen(object):
|
|||
err_msg = err_msg.decode(errors="surrogatepass")
|
||||
if issubclass(child_exception_type, OSError) and hex_errno:
|
||||
errno_num = int(hex_errno, 16)
|
||||
child_exec_never_called = (err_msg == "noexec")
|
||||
if child_exec_never_called:
|
||||
err_msg = ""
|
||||
if errno_num != 0:
|
||||
err_msg = os.strerror(errno_num)
|
||||
if errno_num == errno.ENOENT:
|
||||
err_msg += ': ' + repr(args[0])
|
||||
if child_exec_never_called:
|
||||
# The error must be from chdir(cwd).
|
||||
err_msg += ': ' + repr(cwd)
|
||||
else:
|
||||
err_msg += ': ' + repr(orig_executable)
|
||||
raise child_exception_type(errno_num, err_msg)
|
||||
raise child_exception_type(err_msg)
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue