-
-
Notifications
You must be signed in to change notification settings - Fork 32.2k
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?
Conversation
Oh, and based on my quick search, I just realized that some systems have |
Marking this as a draft (while it is WIP). |
The |
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.
Please add an entry in What's New.
Thanks! My experimentation led me to the same conclusion that determining the problematic path might not be feasible. Having both paths in the exception message seems like a good solution; I will look into it. |
Co-authored-by: Serhiy Storchaka <[email protected]>
…wd when using posix_spawn.
611a339
to
12553e1
Compare
Sorry it took me so long, but I finally found some time to move this further. The exception is now better, although the fact that it's not easily possible to find out whether it's the command or |
Here is how the exception looks now:
|
Py_XDECREF(*cwd); | ||
*cwd = path; |
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_CHDIR
can be passed multiple times with different arguments. In thet case the temporary bytes object saved in *cwd
can be deallocated, and the posix_spawn_file_actions_addchdir_np()
argument can became a bad pointer.
I think that we need to use temp_buffer
here.
Please add a test for posix_spawn()
with multiple POSIX_SPAWN_CHDIR
actions.
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_CHDIR
actions.
We can either:
-
call
posix_spawn_file_actions_addchdir_np
for eachPOSIX_SPAWN_CHDIR
in which caseposix_spawn
will 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 cwd
always 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_np
also affects how files are found for later posix_spawn_file_actions_add_open
, so you need to do them all.
@@ -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 comment
The 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 PyErr_SetFromErrnoWithFilenameObjects()
(note s
at end) with too path arguments? It will perhaps not work if there are multiple POSIX_SPAWN_CHDIR
actions, but this is an extremely uncommon case.
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.
The problem with PyErr_SetFromErrnoWithFilenameObjects
is that the exception looks like this:
File "/usr/lib/python3.13/subprocess.py", line 1799, in _posix_spawn
self.pid = os.posix_spawn(executable, args, env, **kwargs)
~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
FileNotFoundError: [Errno 2] No such file or directory: '/usr/bin/ls' -> b'/nonexistent'
and I don't like the arrow, which is why I used the PyErr_Format
. But otherwise it works nicely and the change is simpler:
-PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, path->object);
+PyErr_SetFromErrnoWithFilenameObjects(PyExc_OSError, path->object, cwd);
Multiple POSIX_SPAWN_CHDIR
actions make it more complicated...
This is a work in progress as there is still one issue to solve:
Running
subprocess.run(["/usr/bin/ls"], cwd="/nonexistent")
should fail with:FileNotFoundError: [Errno 2] No such file or directory: '/nonexistent'
but with this PR, it fails with:
FileNotFoundError: [Errno 2] No such file or directory: '/usr/bin/ls'
which is incorrect, because it's not '/usr/bin/ls' that is missing, it's the directory. I have yet to determine how to fix this.
(this also causes
test.test_subprocess.POSIXProcessTestCase.test_exception_cwd
to fail).📚 Documentation preview 📚: https://cpython-previews--114468.org.readthedocs.build/