Skip to content

stty: do not write settings back for query-only arguments - #13950

Open
m0g3r wants to merge 2 commits into
uutils:mainfrom
m0g3r:stty-no-tcsetattr-for-queries
Open

stty: do not write settings back for query-only arguments#13950
m0g3r wants to merge 2 commits into
uutils:mainfrom
m0g3r:stty-no-tcsetattr-for-queries

Conversation

@m0g3r

@m0g3r m0g3r commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Fixes #13722.

stty size only reads the terminal, but every invocation carrying settings arguments finished with an unconditional tcsetattr. From a background process group POSIX requires the kernel to raise SIGTTOU, whose default disposition stops the process, so stty size off the foreground hangs with no diagnostic and never reaps.

tcsetattr is now called only when at least one parsed argument actually changes the terminal settings. ArgOptions::Print does not, so stty size takes the same path it already took for printing and then stops.

Test

A unit test covers the predicate directly, since reproducing SIGTTOU needs a controlling terminal and a background process group, which the test harness does not provide.

Checked by hand against a pty that size still reports dimensions, that rows/columns still apply, and that -a is unaffected:

stty -F pty size          -> 0 0
stty -F pty rows 40 columns 100
stty -F pty size          -> 40 100
stty -F pty -a            -> speed 38400 baud; rows 40; columns 100; line = 0; ...

cargo test -p uu_stty 27 passed, the stty integration suite 53 passed / 33 ignored, cargo clippy -p uu_stty --all-targets -- -D warnings clean.

Note this touches the same line as #13893. If that lands first the verification it adds should move inside this guard, since there is nothing to verify when the settings were never written.


Written with AI assistance. I have reviewed the diff and verified the behaviour against a pty myself.

`stty size` is a query, but any invocation carrying settings arguments
ended with an unconditional `tcsetattr`. POSIX requires the kernel to
raise SIGTTOU on `tcsetattr` from a background process group, and its
default disposition stops the process, so `stty size` run off the
foreground hangs with no diagnostic and never reaps.

Only call `tcsetattr` when at least one argument actually changes the
terminal settings. `Print` arguments do not.

Fixes uutils#13722

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

Binary size comparison:

Individual binary size comparison VS main (threshold: >=5% AND >=4 KB).

Total size of compared binaries: 149.02 MB (+92 KB, +0.06%)

Significant per-binary changes:
  [           1.10 MB ->    1.18 MB  (+76 KB, +6.74%)
  mkdir       1.10 MB ->    1.17 MB  (+76 KB, +6.76%)
  mknod       1.09 MB ->    1.17 MB  (+76 KB, +6.79%)
  test        1.10 MB ->    1.18 MB  (+76 KB, +6.74%)
  install     1.25 MB ->    1.32 MB  (+72 KB, +5.62%)
  mkfifo      1.09 MB ->    1.16 MB  (+72 KB, +6.45%)
  chmod       1.15 MB ->    1.22 MB  (+68 KB, +5.76%)

@sylvestre

Copy link
Copy Markdown
Contributor

Please also add a test in test_stty.rs

Add a regression test for the SIGTTOU stop this change fixes. The test
allocates a PTY, gives a helper its own session and controlling terminal,
then runs `stty size` from a background process group with SIGTTOU
restored to its default disposition and asserts it exits normally rather
than being stopped.

Verified against the fix: it passes with the patch, and reverting
src/uu/stty/src/stty.rs to its pre-fix state makes it fail with "`stty
size` was stopped by SIGTTOU in a background process group" (signal 22).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

GNU testsuite comparison:

Skip an intermittent issue tests/cut/bounded-memory (fails in this run but passes in the 'main' branch)
Skip an intermittent issue tests/date/date-locale-hour (fails in this run but passes in the 'main' branch)
Skip an intermittent issue tests/pr/bounded-memory (fails in this run but passes in the 'main' branch)
Skipping an intermittent issue tests/rm/isatty (passes in this run but fails in the 'main' branch)

@codspeed-hq

codspeed-hq Bot commented Aug 16, 2026

Copy link
Copy Markdown

Merging this PR will degrade performance by 3.02%

⚠️ Different runtime environments detected

Some benchmarks with significant performance changes were compared across different runtime environments,
which may affect the accuracy of the results.

Open the report in CodSpeed to investigate

❌ 1 regressed benchmark
✅ 352 untouched benchmarks
⏩ 50 skipped benchmarks1

Warning

Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Mode Benchmark BASE HEAD Efficiency
Simulation du_wide_tree[(5000, 500)] 19.7 ms 20.3 ms -3.02%

Tip

Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.


Comparing m0g3r:stty-no-tcsetattr-for-queries (93d7b2d) with main (5633f03)

Open in CodSpeed

Footnotes

  1. 50 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

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.

stty size hangs forever (SIGTTOU) when run from a background process group

2 participants