-
-
Notifications
You must be signed in to change notification settings - Fork 33.3k
WIP: gh-114467: Support posix_spawn in subprocess.Popen with cwd != None #114468
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
base: main
Are you sure you want to change the base?
Changes from all commits
9c1aefc
655e555
915e021
6a1b61a
0be683f
12553e1
d4c31c1
7f77bf9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7127,6 +7127,9 @@ enum posix_spawn_file_actions_identifier { | |
| #ifdef HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCLOSEFROM_NP | ||
| ,POSIX_SPAWN_CLOSEFROM | ||
| #endif | ||
| #ifdef HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR_NP | ||
| ,POSIX_SPAWN_CHDIR | ||
| #endif | ||
| }; | ||
|
|
||
| #if defined(HAVE_SCHED_SETPARAM) || defined(HAVE_SCHED_SETSCHEDULER) || defined(POSIX_SPAWN_SETSCHEDULER) || defined(POSIX_SPAWN_SETSCHEDPARAM) | ||
|
|
@@ -7277,7 +7280,7 @@ parse_posix_spawn_flags(PyObject *module, const char *func_name, PyObject *setpg | |
| static int | ||
| parse_file_actions(PyObject *file_actions, | ||
| posix_spawn_file_actions_t *file_actionsp, | ||
| PyObject *temp_buffer) | ||
| PyObject *temp_buffer, PyObject** cwd) | ||
| { | ||
| PyObject *seq; | ||
| PyObject *file_action = NULL; | ||
|
|
@@ -7384,6 +7387,27 @@ parse_file_actions(PyObject *file_actions, | |
| } | ||
| break; | ||
| } | ||
| #endif | ||
| #ifdef HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR_NP | ||
| case POSIX_SPAWN_CHDIR: { | ||
| PyObject *path; | ||
| if (!PyArg_ParseTuple(file_action, "OO&" | ||
| ";A chdir file_action tuple must have 2 elements", | ||
| &tag_obj, PyUnicode_FSConverter, &path)) | ||
| { | ||
| goto fail; | ||
| } | ||
| errno = posix_spawn_file_actions_addchdir_np(file_actionsp, | ||
| PyBytes_AS_STRING(path)); | ||
| if (errno) { | ||
| posix_error(); | ||
| Py_DECREF(path); | ||
| goto fail; | ||
| } | ||
| Py_XDECREF(*cwd); | ||
| *cwd = path; | ||
| break; | ||
| } | ||
| #endif | ||
| default: { | ||
| PyErr_SetString(PyExc_TypeError, | ||
|
|
@@ -7421,6 +7445,7 @@ py_posix_spawn(int use_posix_spawnp, PyObject *module, path_t *path, PyObject *a | |
| Py_ssize_t argc, envc; | ||
| PyObject *result = NULL; | ||
| PyObject *temp_buffer = NULL; | ||
| PyObject *cwd = NULL; | ||
| pid_t pid; | ||
| int err_code; | ||
|
|
||
|
|
@@ -7486,7 +7511,7 @@ py_posix_spawn(int use_posix_spawnp, PyObject *module, path_t *path, PyObject *a | |
| if (!temp_buffer) { | ||
| goto exit; | ||
| } | ||
| if (parse_file_actions(file_actions, &file_actions_buf, temp_buffer)) { | ||
| if (parse_file_actions(file_actions, &file_actions_buf, temp_buffer, &cwd)) { | ||
| goto exit; | ||
| } | ||
| file_actionsp = &file_actions_buf; | ||
|
|
@@ -7518,6 +7543,17 @@ py_posix_spawn(int use_posix_spawnp, PyObject *module, path_t *path, PyObject *a | |
|
|
||
| if (err_code) { | ||
| errno = err_code; | ||
| #ifdef HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR_NP | ||
| if (errno == ENOENT && cwd != NULL) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is not the only common error possible here. For example, you can get EPERM or EACCES if any of the executable or the cwd paths are not readable for the user, or ENAMETOOLONG if they are too long, or ELOOP if they contain symlink loops, or ENOTDIR if any of intermediate path component is not a directory. It is not possible to handle all errors. Maybe use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The problem with and I don't like the arrow, which is why I used the -PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, path->object);
+PyErr_SetFromErrnoWithFilenameObjects(PyExc_OSError, path->object, cwd);Multiple |
||
| /* ENOENT can occur when either the path of the executable or the | ||
| * cwd given via file_actions doesn't exist. Since it's not feasible | ||
| * to determine which of those paths caused the problem, we return | ||
| * an exception with both. */ | ||
| PyErr_Format(PyExc_FileNotFoundError, "Either '%S' or '%s' doesn't exist.", | ||
| path->object, PyBytes_AS_STRING(cwd)); | ||
| goto exit; | ||
| } | ||
| #endif | ||
| PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, path->object); | ||
| goto exit; | ||
| } | ||
|
|
@@ -7539,6 +7575,7 @@ py_posix_spawn(int use_posix_spawnp, PyObject *module, path_t *path, PyObject *a | |
| if (argvlist) { | ||
| free_string_array(argvlist, argc); | ||
| } | ||
| Py_XDECREF(cwd); | ||
| Py_XDECREF(temp_buffer); | ||
| return result; | ||
| } | ||
|
|
@@ -17576,6 +17613,9 @@ all_ins(PyObject *m) | |
| #ifdef HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCLOSEFROM_NP | ||
| if (PyModule_AddIntMacro(m, POSIX_SPAWN_CLOSEFROM)) return -1; | ||
| #endif | ||
| #ifdef HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR_NP | ||
| if (PyModule_AddIntMacro(m, POSIX_SPAWN_CHDIR)) return -1; | ||
| #endif | ||
| #endif | ||
|
|
||
| #if defined(HAVE_SPAWNV) || defined (HAVE_RTPSPAWN) | ||
|
|
||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
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.
POSIX_SPAWN_CHDIRcan be passed multiple times with different arguments. In thet case the temporary bytes object saved in*cwdcan be deallocated, and theposix_spawn_file_actions_addchdir_np()argument can became a bad pointer.I think that we need to use
temp_bufferhere.Please add a test for
posix_spawn()with multiplePOSIX_SPAWN_CHDIRactions.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.
Yeah, I am not sure how to handle multiple
POSIX_SPAWN_CHDIRactions.We can either:
call
posix_spawn_file_actions_addchdir_npfor eachPOSIX_SPAWN_CHDIRin which caseposix_spawnwill fail when any of those doesn't exist (or when other error occurs as you pointed out below) even if that one wouldn't be the final one. In such case, the error message might be pretty big.we can omit all but the last one, in which case it will not behave as some might expect. But we would have only two paths to display in the error message.
As for the bad pointer, it's possible, but
cwdalways holds the latest one so whether it's called with one or muliple ones shouldn't matter here? But I might be completely wrong. Also, if we want to save all the paths (in case 1. is the prefered one), that might change.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.
posix_spawn_file_actions_addchdir_npalso affects how files are found for laterposix_spawn_file_actions_add_open, so you need to do them all.