-
Notifications
You must be signed in to change notification settings - Fork 29.6k
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
Background node process corrupts terminal state with tcsetattr() on exit #35536
Comments
In addition to being generally less unfriendly, this works around a bug in Node.js that causes webpack-dev-server to corrupt the terminal state when exiting as a background process. nodejs/node#35536 Signed-off-by: Anders Kaseorg <[email protected]>
In addition to being generally less unfriendly, this works around a bug in Node.js that causes webpack-dev-server to corrupt the terminal state when exiting as a background process. nodejs/node#35536 Signed-off-by: Anders Kaseorg <[email protected]>
In addition to being generally less unfriendly, this works around a bug in Node.js that causes webpack-dev-server to corrupt the terminal state when exiting as a background process. nodejs/node#35536 Signed-off-by: Anders Kaseorg <[email protected]>
In addition to being generally less unfriendly, this works around a bug in Node.js that causes webpack-dev-server to corrupt the terminal state when exiting as a background process. nodejs/node#35536 Signed-off-by: Anders Kaseorg <[email protected]>
In addition to being generally more correct, this works around a bug in Node.js that causes webpack-dev-server to corrupt the terminal state when exiting as a background process. nodejs/node#35536 Signed-off-by: Anders Kaseorg <[email protected]>
In addition to being generally more correct, this works around a bug in Node.js that causes webpack-dev-server to corrupt the terminal state when exiting as a background process. nodejs/node#35536 Signed-off-by: Anders Kaseorg <[email protected]>
In addition to being generally more correct, this works around a bug in Node.js that causes webpack-dev-server to corrupt the terminal state when exiting as a background process. nodejs/node#35536 Signed-off-by: Anders Kaseorg <[email protected]>
In addition to being generally more correct, this works around a bug in Node.js that causes webpack-dev-server to corrupt the terminal state when exiting as a background process. nodejs/node#35536 Signed-off-by: Anders Kaseorg <[email protected]>
In addition to being generally more correct, this works around a bug in Node.js that causes webpack-dev-server to corrupt the terminal state when exiting as a background process. nodejs/node#35536 Signed-off-by: Anders Kaseorg <[email protected]>
able to reproduce in linux, not sure what implications are for reverting the two commits in the linked PR. tag. Tagging as a bug. |
This also reproduces in Node 20.5.1 and 18.16.1 by:
I have a probably unusual use case where I hit this a lot and it's frustrating (I wrote a simple music player using Node that exits after playing the song). I concur that the behavior should be changed. |
I don't think reverting #24260 or #28535 is realistically an option because that impacts a lot more users than this bug report. I personally don't care if node suspends on SIGTTOU or not, but enough people did to flag it as a bug. My advice is to simply not background node but, if you absolutely have to, then as a workaround, reopen file descriptors 0-2 to /dev/null right before exiting. That will stop node from issuing the tcsetattr() calls. Unless you or someone else has an actionable way forward, I'll go and close this issue in a few days. |
Of course #28535 impacts many users given #24260. That’s why the proposal is to revert #24260 and #28535. If Node does not make unrequested changes to the terminal state on exit, then there will be no This issue affects more people than those who realize it, because it is so unexpected. It’s not just about a Node program running in the background; that’s just the most reliable way to reproduce. It also makes for a race condition that nondeterministically breaks piping a Node program to a pager, because the Node program exits while the pager is still supposed to be in charge of the terminal mode. See for example
Node programs that intentionally modify the terminal state are rare. It is the responsibility of those programs to restore the terminal state, and it’s reasonable to expect users to avoid running those programs in the background or piping them to a pager. But it’s not reasonable to say that typical programs that just |
That seems true to me. As a case in point, I've been hitting this bug regularly for years, and it only just occurred to me to try to isolate the cause, figuring out it was a bug in Node and not my own program, and perform some lucky web searches that happened to lead me to this issue. I skimmed #24260 and the issues it was trying to solve. I might be a little out of my depth here, but would it be reasonable to only make this |
Just to be clear: I'm saying reverting isn't an option. We're essentially at a local optimum where things work well enough for most users, and while I sympathize with your use case, anything that negatively impacts the silent majority is a no-go.
With all due respect, you're betraying a lack of insight here in how node works under the hood. It goes to great lengths to provide an async runtime and that includes things like console.log.
I considered that when I wrote #24260 but it's unreliable with libraries like blessed (popular, ca. 10M downloads/month) because not all tty state changes are visible to node. The unconditional reset acts as a fail-safe that restores it to a sane state on program exit. A command line flag to disable the current behavior might be an acceptable way forward (because that makes it opt-in) but to set expectations, I don't plan on working on or reviewing that myself, you'll have to find someone else. |
might the proposed reverts fix #42433 too? i currently have a very strange case where this occurs when node should just cleanly exit. |
ResetStdio
insrc/node.cc
In Bash, run the following:
This launches
node -e 'setTimeout(() => {}, 2000)'
in the background andsleep 1
in the foreground. After 1 second, control returns to Bash. After 2 seconds, Node exits and corrupts Bash’s terminal state:^[[A
,^[[B
,^[[C
,^[[D
instead of scrolling through the Bash history or moving the insert point,^A
and^E
instead of jumping to the beginning and end of the command, etc.This happens when the
ResetStdio
handler usestcsetattr
to “restore” the terminal to the state it was in when Node started (#24260). This interferes with Bash, which uses and expects a different terminal state thansleep 1
.(The bug is sometimes reproducible without the
sleep 1
depending on whether Node records the initial terminal state before Bash updates it, but thesleep 1
makes it reliable.)Normally, the terminal state would be protected from such undesired modifications by a background process: the kernel generates
SIGTTOU
to suspend the process until it’s brought to the foreground. ButResetStdio
now deliberately overrides this protection by blockingSIGTTOU
(#28535).IMO, both #24260 and #28535 should be reverted. Node is a programming language; it should never make changes to the terminal state that programs did not request.
The text was updated successfully, but these errors were encountered: