Skip to content

Commit d669339

Browse files
committed
Implement better error reporting for non-existent executable and/or cwd when using posix_spawn.
1 parent 28d13e5 commit d669339

2 files changed

Lines changed: 18 additions & 3 deletions

File tree

Lib/test/test_subprocess.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2018,6 +2018,7 @@ def _get_chdir_exception(self):
20182018
self._nonexistent_dir)
20192019
return desired_exception
20202020

2021+
@mock.patch("subprocess._HAVE_POSIX_SPAWN_CHDIR", new=False)
20212022
def test_exception_cwd(self):
20222023
"""Test error in the child raised in the parent for a bad cwd."""
20232024
desired_exception = self._get_chdir_exception()

Modules/posixmodule.c

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7760,7 +7760,7 @@ parse_posix_spawn_flags(PyObject *module, const char *func_name, PyObject *setpg
77607760
static int
77617761
parse_file_actions(PyObject *file_actions,
77627762
posix_spawn_file_actions_t *file_actionsp,
7763-
PyObject *temp_buffer)
7763+
PyObject *temp_buffer, PyObject** cwd)
77647764
{
77657765
PyObject *seq;
77667766
PyObject *file_action = NULL;
@@ -7884,7 +7884,8 @@ parse_file_actions(PyObject *file_actions,
78847884
Py_DECREF(path);
78857885
goto fail;
78867886
}
7887-
Py_DECREF(path);
7887+
Py_XDECREF(cwd);
7888+
*cwd = path;
78887889
break;
78897890
}
78907891
#endif
@@ -7924,6 +7925,7 @@ py_posix_spawn(int use_posix_spawnp, PyObject *module, path_t *path, PyObject *a
79247925
Py_ssize_t argc, envc;
79257926
PyObject *result = NULL;
79267927
PyObject *temp_buffer = NULL;
7928+
PyObject *cwd = NULL;
79277929
pid_t pid;
79287930
int err_code;
79297931

@@ -7995,7 +7997,7 @@ py_posix_spawn(int use_posix_spawnp, PyObject *module, path_t *path, PyObject *a
79957997
if (!temp_buffer) {
79967998
goto exit;
79977999
}
7998-
if (parse_file_actions(file_actions, &file_actions_buf, temp_buffer)) {
8000+
if (parse_file_actions(file_actions, &file_actions_buf, temp_buffer, &cwd)) {
79998001
goto exit;
80008002
}
80018003
file_actionsp = &file_actions_buf;
@@ -8027,6 +8029,17 @@ py_posix_spawn(int use_posix_spawnp, PyObject *module, path_t *path, PyObject *a
80278029

80288030
if (err_code) {
80298031
errno = err_code;
8032+
#ifdef HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR_NP
8033+
if (errno == ENOENT && cwd != NULL) {
8034+
/* ENOENT can occur when either the path of the executable or the
8035+
* cwd given via file_actions doesn't exist. Since it's not feasible
8036+
* to determine which of those paths caused the problem, we return
8037+
* an exception with both. */
8038+
PyErr_Format(PyExc_FileNotFoundError, "Either '%S' or '%s' doesn't exist.",
8039+
path->object, PyBytes_AS_STRING(cwd));
8040+
goto exit;
8041+
}
8042+
#endif
80308043
PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, path->object);
80318044
goto exit;
80328045
}
@@ -8048,6 +8061,7 @@ py_posix_spawn(int use_posix_spawnp, PyObject *module, path_t *path, PyObject *a
80488061
if (argvlist) {
80498062
free_string_array(argvlist, argc);
80508063
}
8064+
Py_XDECREF(cwd);
80518065
Py_XDECREF(temp_buffer);
80528066
return result;
80538067
}

0 commit comments

Comments
 (0)