Skip to content

build: block SIGTTOU before calling tcsetattr() - #28535

Closed
bnoordhuis wants to merge 1 commit into
nodejs:masterfrom
bnoordhuis:fix28530
Closed

build: block SIGTTOU before calling tcsetattr()#28535
bnoordhuis wants to merge 1 commit into
nodejs:masterfrom
bnoordhuis:fix28530

Conversation

@bnoordhuis

Copy link
Copy Markdown
Member

We might be a background job that doesn't own the TTY so block SIGTTOU
before making the tcsetattr() call, otherwise that signal suspends us.

This is a better fix than PR #28490 for issue #28479.

Fixes: #28530
Fixes: #28479
Refs: #28490

@nodejs-github-botnodejs-github-bot added the c++ Issues and PRs that require attention from people who are familiar with C++. label Jul 4, 2019
@BridgeAR

Copy link
Copy Markdown
Member

Would it make sense to add a regression test for this as well?

@TrottTrott left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason not to have a test? (I'm thinking there's no reason not to have something that checks if we're on Windows and skips, otherwise uses child_process to run cat <(node -v). But maybe tty vs. no tty or whatever will mess stuff up? In that case, maybe accept error codes on exit, and the test just makes sure the command actually returns, error or no?)

@cjihrigcjihrig left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Why is the commit subsystem build instead of src?

We might be a background job that doesn't own the TTY so block SIGTTOU
before making the tcsetattr() call, otherwise that signal suspends us.
This is a better fix than PR nodejs#28490 for issue nodejs#28479.
Fixes: nodejs#28530Fixes: nodejs#28479
Refs: nodejs#28490
@bnoordhuis

Copy link
Copy Markdown
MemberAuthor

But maybe tty vs. no tty or whatever will mess stuff up?

Yes. Two issues make writing a test hard:

  1. cat <(...) is a bash-ism but not all CI machines have /bin/bash

  2. bash -i doesn't work from a pseudo-tty test, no job control

IOW, I can't see a way to recreate the circumstances of the hang. If anyone has a good suggestion I'd like to hear it.

Why is the commit subsystem build instead of src?

I have no idea, I have no recollection of writing that. :-) I've fixed it up.

@sam-githubsam-github left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. node doesn't have PTY and job control APIs, so I'm not surprised that its not possible to emulate what a job-control shell does to trigger this problem in our tests.

@Trott

Trott commented Jul 5, 2019

Copy link
Copy Markdown
Member
  1. cat <(...) is a bash-ism but not all CI machines have /bin/bash

Test can check for existence of /bin/bash or run which bash and check the results?

  1. bash -i doesn't work from a pseudo-tty test, no job control

Yeah, this one is harder unless running a bash script in the fixtures dir can somehow solve it?

Anyway, totally not blocking on this.

@bnoordhuis

Copy link
Copy Markdown
MemberAuthor

Yeah, this one is harder unless running a bash script in the fixtures dir can somehow solve it?

Just to confirm: I spent considerable time today trying to make it work and I didn't find a way.

@TrottTrott added the author ready PRs that have at least one approval, no pending requests for changes, and a CI started. label Jul 5, 2019
@nodejs-github-bot

This comment has been minimized.

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@addaleax

Copy link
Copy Markdown
Member

Landed in b06ce0b

@addaleaxaddaleax closed this Jul 6, 2019
pullBot pushed a commit to Mattlk13/node that referenced this pull request Jul 6, 2019
We might be a background job that doesn't own the TTY so block SIGTTOU
before making the tcsetattr() call, otherwise that signal suspends us.
This is a better fix than PR nodejs#28490 for issue nodejs#28479.
Fixes: nodejs#28530Fixes: nodejs#28479
Refs: nodejs#28490
PR-URL: nodejs#28535
Reviewed-By: Gireesh Punathil <gpunathi@in.ibm.com>
Reviewed-By: Richard Lau <riclau@uk.ibm.com>
Reviewed-By: Rich Trott <rtrott@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Sam Roberts <vieuxtech@gmail.com>
@bnoordhuis
bnoordhuis deleted the fix28530 branch July 10, 2019 06:28
targos pushed a commit that referenced this pull request Jul 20, 2019
We might be a background job that doesn't own the TTY so block SIGTTOU
before making the tcsetattr() call, otherwise that signal suspends us.
This is a better fix than PR #28490 for issue #28479.
Fixes: #28530Fixes: #28479
Refs: #28490
PR-URL: #28535
Reviewed-By: Gireesh Punathil <gpunathi@in.ibm.com>
Reviewed-By: Richard Lau <riclau@uk.ibm.com>
Reviewed-By: Rich Trott <rtrott@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Sam Roberts <vieuxtech@gmail.com>
This was referenced Jul 23, 2019
@andersk

Copy link
Copy Markdown
Contributor

I think this was the wrong solution. SIGTTOU is supposed to protect the terminal state from being corrupted by a background process while the foreground process is using it. With SIGTTOU blocked, a Node background process now does exactly that: #35536.

The real bug here, IMO, is Node trying to call tcsetattr() at exit at all. Node is a programming language; it should never make changes to the terminal state that programs did not request.

sunshowers added a commit to nextest-rs/nextest that referenced this pull request Jan 3, 2026
When a test spawns an interactive shell (e.g., `zsh -ic`), the shell
opens `/dev/tty` directly and calls `tcsetpgrp` to become the foreground
process group. When the shell exits, nextest is now in the background.
If nextest then tries to restore terminal state via `tcsetattr`, it
receives SIGTTOU and gets suspended.
The fix is to block SIGTTOU around `tcsetattr` calls using
`sigprocmask`. This is a well-established pattern used by:
- less: https://github.com/gwsw/less/blob/e77e117/signal.c#L213-L221 - Node.js: nodejs/node#28535
Also adds a test helper binary (`grab-foreground`) that simulates what
interactive shells do, and an ignored integration test to verify the
fix. The test is currently ignored because it requires a version of nextest
with the fix -- we'll un-ignore it once a new version of nextest is out.
Fixes: #2878
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

author readyPRs that have at least one approval, no pending requests for changes, and a CI started.c++Issues and PRs that require attention from people who are familiar with C++.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

cat <(node -v) never exits after >= 12.5.0 CHECK failure in ResetStdio on >=12.5.0

10 participants

@bnoordhuis@BridgeAR@Trott@nodejs-github-bot@addaleax@andersk@sam-github@cjihrig@richardlau@gireeshpunathil