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

uv_tty_reset_mode doesn't work as advertised if original handle is closed #4398

Open
saghul opened this issue May 6, 2024 · 5 comments
Open

Comments

@saghul
Copy link
Member

saghul commented May 6, 2024

In the docs we describe it like so:

To be called when the program exits. Resets TTY settings to default values for the next process to take over.

That somewhat (together with the fact Node uses it that way too) suggests one can call it from an atexit handler to restore the original mode.

Well, that only works if the tty handle isn't closed. Since we reopen the fd when it refers to a tty (the typical case of a REPL), the internal orig_termios_fd reference will point to the duplicated fd, not the real one. When the handle is closed that fd will be invalid and uv_tty_reset_mode will fail with EBADF.

I guess there are 2 bugs here:

  1. We should reset orig_termios_fd if the tty handle is closed, since the fd will become invalid.

  2. Can we save the original fd so we can restore the mode even after the tty handle is closed? Not sure about this one since we don't store the fd but just the duplicated one. An option (strawman proposal!) could be some UV_TTY_MODE_RESET_ON_CLOSE flag that can be or-ed with the mode, so we auto-reset it upon handle close.

Thoughts?

  • Version: all since we started dup-ing the tty fd
  • Platform: Only tested on Darwin, but I suspect all Unices
@vtjnash
Copy link
Member

vtjnash commented May 6, 2024

Probably also a duplicate of #2062 where the dup2 behavior interferes with the correct behavior of native libraries and uv_spawn also and that native libraries can corrupt libuv state (fwiw, Julia always passes in dup of stdio handles instead of 0,1,2 so that those issues do not occur)

@saghul
Copy link
Member Author

saghul commented May 6, 2024

Similar yeah. I guess my reason to think this one is slightly different is that we have dedicated functionality to interact with the outside world, but it has some iinteresting caveats.

bnoordhuis added a commit to bnoordhuis/libuv that referenced this issue May 7, 2024
Libuv stores the `struct termios` for use inside uv_tty_reset_mode().

Node.js uses said function to restore the tty to its original mode
on SIGINT or SIGTERM, when there is no opportunity to shut down the
process normally.

Track uv_tty_t handle closing, otherwise we might be trying to use a
stale termios.

The current solution is not ideal because there can be multiple handles
that refer to the same tty/pty and, for various reasons, we can't really
determine when we close the last handle. The last handle may not even be
inside the current process.

Still, all things considered, it's probably (hopefully!) an improvement
over the status quo.

Refs: libuv#4398
@bnoordhuis
Copy link
Member

We should reset orig_termios_fd if the tty handle is closed, since the fd will become invalid.

#4399 - imperfect but ceteris paribus an improvement

@vtjnash
Copy link
Member

vtjnash commented May 7, 2024

the internal orig_termios_fd reference will point to the duplicated fd, not the real one

To be clear, my recollection is that libuv then calls dup2 to destroy the original fd so that it can point to the "real" one not the duplicated one (which is the bug in #2062)

Secondly, should we add a uv_tty_capture_mode(uv_os_handle_t fd) function, so that this applications can avoid having this code be conditional on whatever pty object first happens to used with it, and so the user could capture the state of fd 0 explicitly instead?

@saghul
Copy link
Member Author

saghul commented May 7, 2024

Not sure, I find the current behavior good, minus a specific case...

The PR Ben made solves it already, so I guess we can get more creative if / when we need to?

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

No branches or pull requests

3 participants