Skip to content

Commit 12553e1

Browse files
committed
Implement better error reporting for non-existent executable and/or cwd when using posix_spawn.
1 parent 0be683f commit 12553e1

File tree

2 files changed

+18
-3
lines changed

2 files changed

+18
-3
lines changed

Lib/test/test_subprocess.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1841,6 +1841,7 @@ def _get_chdir_exception(self):
18411841
self._nonexistent_dir)
18421842
return desired_exception
18431843

1844+
@mock.patch("subprocess._HAVE_POSIX_SPAWN_CHDIR", new=False)
18441845
def test_exception_cwd(self):
18451846
"""Test error in the child raised in the parent for a bad cwd."""
18461847
desired_exception = self._get_chdir_exception()

Modules/posixmodule.c

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7280,7 +7280,7 @@ parse_posix_spawn_flags(PyObject *module, const char *func_name, PyObject *setpg
72807280
static int
72817281
parse_file_actions(PyObject *file_actions,
72827282
posix_spawn_file_actions_t *file_actionsp,
7283-
PyObject *temp_buffer)
7283+
PyObject *temp_buffer, PyObject** cwd)
72847284
{
72857285
PyObject *seq;
72867286
PyObject *file_action = NULL;
@@ -7404,7 +7404,8 @@ parse_file_actions(PyObject *file_actions,
74047404
Py_DECREF(path);
74057405
goto fail;
74067406
}
7407-
Py_DECREF(path);
7407+
Py_XDECREF(cwd);
7408+
*cwd = path;
74087409
break;
74097410
}
74107411
#endif
@@ -7444,6 +7445,7 @@ py_posix_spawn(int use_posix_spawnp, PyObject *module, path_t *path, PyObject *a
74447445
Py_ssize_t argc, envc;
74457446
PyObject *result = NULL;
74467447
PyObject *temp_buffer = NULL;
7448+
PyObject *cwd = NULL;
74477449
pid_t pid;
74487450
int err_code;
74497451

@@ -7509,7 +7511,7 @@ py_posix_spawn(int use_posix_spawnp, PyObject *module, path_t *path, PyObject *a
75097511
if (!temp_buffer) {
75107512
goto exit;
75117513
}
7512-
if (parse_file_actions(file_actions, &file_actions_buf, temp_buffer)) {
7514+
if (parse_file_actions(file_actions, &file_actions_buf, temp_buffer, &cwd)) {
75137515
goto exit;
75147516
}
75157517
file_actionsp = &file_actions_buf;
@@ -7541,6 +7543,17 @@ py_posix_spawn(int use_posix_spawnp, PyObject *module, path_t *path, PyObject *a
75417543

75427544
if (err_code) {
75437545
errno = err_code;
7546+
#ifdef HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR_NP
7547+
if (errno == ENOENT && cwd != NULL) {
7548+
/* ENOENT can occur when either the path of the executable or the
7549+
* cwd given via file_actions doesn't exist. Since it's not feasible
7550+
* to determine which of those paths caused the problem, we return
7551+
* an exception with both. */
7552+
PyErr_Format(PyExc_FileNotFoundError, "Either '%S' or '%s' doesn't exist.",
7553+
path->object, PyBytes_AS_STRING(cwd));
7554+
goto exit;
7555+
}
7556+
#endif
75447557
PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, path->object);
75457558
goto exit;
75467559
}
@@ -7562,6 +7575,7 @@ py_posix_spawn(int use_posix_spawnp, PyObject *module, path_t *path, PyObject *a
75627575
if (argvlist) {
75637576
free_string_array(argvlist, argc);
75647577
}
7578+
Py_XDECREF(cwd);
75657579
Py_XDECREF(temp_buffer);
75667580
return result;
75677581
}

0 commit comments

Comments
 (0)