Skip to content
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

bpo-26228: Fix pty EOF handling #12049

Merged
merged 2 commits into from
Aug 11, 2021

Conversation

RadicalZephyr
Copy link
Contributor

@RadicalZephyr RadicalZephyr commented Feb 26, 2019

I took a shot at fixing this in a smaller more targeted patch. I don't have a BSD system to test this on, but I think this should still solve the major issue of pty.spawn hanging on platforms that don't raise an error. In addition, pty.spawn should now ALWAYS return the terminal to the previous settings.

Co-authored with @reillysiemens.

https://bugs.python.org/issue26228

@RadicalZephyr
Copy link
Contributor Author

@eamanu I would love to address your comments and move this closer to being merged, but I don't really understand what you were getting at. If you could provide some clarifications to the questions I asked that would be really helpful. Thanks!

@RadicalZephyr RadicalZephyr force-pushed the bpo-26228-fix-pty-eof-handling branch from 3841527 to bc5119e Compare May 21, 2019 01:36
@csabella csabella requested review from gpshead and vadmium May 21, 2019 12:12
@RadicalZephyr RadicalZephyr force-pushed the bpo-26228-fix-pty-eof-handling branch from ff4cbda to 03ead99 Compare May 23, 2019 06:45
@reillysiemens
Copy link
Contributor

@RadicalZephyr: Looks like there are some conflicts with this, would you be able to rebase or otherwise resolve those?

@csabella, @gpshead, @vadmium, @eamanu: Do any of y'all see further blockers to this being merged? 🤔

@RadicalZephyr RadicalZephyr force-pushed the bpo-26228-fix-pty-eof-handling branch from 03ead99 to 35d6377 Compare August 24, 2020 08:51
@RadicalZephyr
Copy link
Contributor Author

@reillysiemens rebased against master 👍

@8vasu
Copy link
Contributor

8vasu commented Aug 31, 2020

Hi.

From 3.10 docs:

In order to force spawn to return before the child process exits an OSError should be thrown

This is a result of ALL OSErrors in _copy() being caught in spawn(). However, this patch removes that except clause. I actually like this change :D It is already a part of some code that I have been writing. This way, unwanted OSErrors will not be ignored. However, docs need to be updated. Also, this needs to be approved by reviewers.

@RadicalZephyr
Copy link
Contributor Author

RadicalZephyr commented Sep 1, 2020

Good catch @8vasu. I've updated the docs a bit to not advertise that throwing OSError from the master_read function will still work to cause spawn to return, and instead suggest returning an empty byte array.

Perhaps that whole clause should just be removed instead, and make the usage of spawn returning before the child process ends not officially supported? I think that particular functionality is a very niche use-case that would be abusing pty.spawn to fork a daemon process but first to do some I/O with it via a pty. I think that use-case is advanced enough that it's outside of the scope of what pty.spawn should be used for.

@8vasu
Copy link
Contributor

8vasu commented Sep 4, 2020

Agreed. In fact, if the child process does not change state, even if you successfully get out of _copy(), you'll still be stuck at the final waitpid() in spawn() [ this is off the top of my head; I have not tested this claim, so please correct me if I am wrong. ]

Anyway, there are several other problems with cpython's pty. A lot of its fallback code is outdated; I contacted the glibc people about this. I am currently using a tiling window manager; every time I resize xterm's X window, the underlying terminal size also gets modified, and the output of commands are laid out incorrectly, making them very hard to read [ no SIGWINCH handling ].

There are much better pty libraries for python on PyPI, but when I want to perform a quick test, I should not have to download and learn how to use third party libraries. I have fixed most of these issues in cpython's pty while keeping it backward compatible: I decided to keep the "except OSError" in spawn() for now. I tested my version on Linux, FreeBSD, OpenBSD, and NetBSD. I have not tested it on Solaris, Illumos, macOS, Cygwin, etc. However, I am afraid that cpython will probably take a decade to merge such changes, given that its primary objective is not systems programming :D After a little more testing, I will make the file available in a separate repository; it will serve as an independent drop-in replacement for cpython's pty.

@RadicalZephyr
Copy link
Contributor Author

I think one of the big concerns with making changes to the existing pty module is breaking backwards compatibility. Perhaps what really needs to happen is to create a new pty2 module, several other modules in the Python standard library that needed substantial reworks. Perhaps your replacement library could be submitted as such! Then pty could be deprecated and pty2 recommended for new code.

@8vasu
Copy link
Contributor

8vasu commented Sep 4, 2020

Fantastic idea. I will admit that I have never done this before. If I was to submit a pull request for a new library, I think I would also be responsible for creating docs, tests, etc. Also, if the new library does not modify certain parts of pty, then I believe that I should import pty in the new library to re-use that code. What is your opinion?

Anyway, I might still make the new library available as a separate download.

@RadicalZephyr
Copy link
Contributor Author

I'm not sure about reusing code from the pty module. I'm not very experienced in engaging with the cpython contribution process. I think maybe the best place to start with getting pty2 going is to chat with the devs on the #python-dev IRC channel on freenode. https://www.python.org/community/irc/

@8vasu
Copy link
Contributor

8vasu commented Sep 5, 2020

Thank you for the suggestion @RadicalZephyr I will try that first.

@8vasu
Copy link
Contributor

8vasu commented Sep 7, 2020

Here you go: https://github.com/8vasu/pypty2 :)

I welcome suggestions and criticisms.

@8vasu
Copy link
Contributor

8vasu commented Sep 16, 2020

I realized that @reillysiemens is a co-author of this. Since https://github.com/8vasu/pypty2 includes a solution of this issue as well, I should include his name in the Acknowledgements file. Does anyone have any objection?

@8vasu
Copy link
Contributor

8vasu commented Sep 16, 2020

Done.

RadicalZephyr and others added 2 commits August 11, 2021 13:43
When both file descriptors gracefully report an error. This presents
custom implementations of *master_read* and *stdin_read* that
accidentally or intentionally return an empty byte string from
blocking the terminal.

Co-Authored-By: Reilly Tucker Siemens <reilly@tuckersiemens.com>
@ambv ambv force-pushed the bpo-26228-fix-pty-eof-handling branch from a8c7a81 to 9f62b82 Compare August 11, 2021 14:23
@ambv ambv added the 🔨 test-with-buildbots Test PR w/ buildbots; report in status section label Aug 11, 2021
@bedevere-bot
Copy link

🤖 New build scheduled with the buildbot fleet by @ambv for commit 9f62b82 🤖

If you want to schedule another build, you need to add the ":hammer: test-with-buildbots" label again.

@bedevere-bot bedevere-bot removed the 🔨 test-with-buildbots Test PR w/ buildbots; report in status section label Aug 11, 2021
@ambv ambv merged commit 81ab8db into python:main Aug 11, 2021
@ambv ambv added needs backport to 3.9 only security fixes needs backport to 3.10 only security fixes labels Aug 11, 2021
@miss-islington
Copy link
Contributor

Thanks @RadicalZephyr for the PR, and @ambv for merging it 🌮🎉.. I'm working now to backport this PR to: 3.10.
🐍🍒⛏🤖

@miss-islington
Copy link
Contributor

Thanks @RadicalZephyr for the PR, and @ambv for merging it 🌮🎉.. I'm working now to backport this PR to: 3.9.
🐍🍒⛏🤖

@miss-islington
Copy link
Contributor

Sorry, @RadicalZephyr and @ambv, I could not cleanly backport this to 3.9 due to a conflict.
Please backport using cherry_picker on command line.
cherry_picker 81ab8db235580317edcb0e559cd4c983f70883f5 3.9

@bedevere-bot
Copy link

GH-27732 is a backport of this pull request to the 3.10 branch.

@bedevere-bot bedevere-bot removed the needs backport to 3.10 only security fixes label Aug 11, 2021
miss-islington pushed a commit to miss-islington/cpython that referenced this pull request Aug 11, 2021
On non-Linux POSIX platforms, like FreeBSD or macOS,
the FD used to read a forked PTY may signal its exit not
by raising an error but by sending empty data to the read
syscall. This case wasn't handled, leading to hanging
`pty.spawn` calls.

Co-authored-by: Reilly Tucker Siemens <reilly@tuckersiemens.com>
Co-authored-by: Łukasz Langa <lukasz@langa.pl>
(cherry picked from commit 81ab8db)

Co-authored-by: Zephyr Shannon <geoffpshannon@gmail.com>
@ambv ambv removed the needs backport to 3.9 only security fixes label Aug 11, 2021
@ambv
Copy link
Contributor

ambv commented Aug 11, 2021

3.9 differs too much for backporting, leaving this behind then.

ambv pushed a commit that referenced this pull request Aug 12, 2021
On non-Linux POSIX platforms, like FreeBSD or macOS,
the FD used to read a forked PTY may signal its exit not
by raising an error but by sending empty data to the read
syscall. This case wasn't handled, leading to hanging
`pty.spawn` calls.

Co-authored-by: Reilly Tucker Siemens <reilly@tuckersiemens.com>
Co-authored-by: Łukasz Langa <lukasz@langa.pl>
(cherry picked from commit 81ab8db)

Co-authored-by: Zephyr Shannon <geoffpshannon@gmail.com>
@vstinner
Copy link
Member

Thanks for the fix! I had headaches fighting with https://bugs.python.org/issue38547

See also my commit 7a51a7e for Solaris/AIX: https://bugs.python.org/issue40140

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants