Skip to content

IO (Unix): fixes blocking forever on incomplete terminal responses - #2653

Merged
CarterLi merged 2 commits into
fastfetch-cli:devfrom
ihsandeniz:fix-term-resp-partial
Oct 28, 2026
Merged

CarterLi merged 2 commits into
fastfetch-cli:devfrom
ihsandeniz:fix-term-resp-partial

Conversation

@ihsandeniz

Copy link
Copy Markdown
Contributor

ffGetTerminalResponse() only polls before the first read(). When the terminal answers with an incomplete response (e.g. \e[4;800 for \e[14t), vsscanf matches fewer than nParams values and the loop calls read() again; with ICANON off and VMIN=1 that call never returns.

This waits with the same FF_IO_TERM_RESP_WAIT_MS timeout before every subsequent read() as well. Tested on Linux with a pty that reports zero pixel size and replies to \e[14t with a full, a split (two writes, 30 ms apart) and a truncated response: before the change the truncated case hangs, after it fastfetch exits normally; full and split responses are still parsed. ctest passes.

Possibly related to #2584 (v2.67.1's --gen-config TUI queried the terminal size on every frame; that query is skipped there since 537635c).

ffGetTerminalResponse() polls only before the first read(). If the terminal
sends a response that is cut short (e.g. `\e[4;800` without the rest), the
following read() in the loop blocks forever because the tty is in
non-canonical mode with VMIN=1.

Wait with the same timeout before every subsequent read() as well.
@ihsandeniz

Copy link
Copy Markdown
Contributor Author

Friendly ping. This still applies cleanly on dev. Happy to change the approach if you had something else in mind for #2584.

@CarterLi

Copy link
Copy Markdown
Member

When the terminal answers with an incomplete response (e.g. \e[4;800 for \e[14t)

Isn't it a bug that should be fixed in the terminal side?

Anyway, the fix should be applied on Windows too.

Same issue as on Unix: ffGetTerminalResponse() waits for input only before
the first ReadFile(). If the terminal answers only part of the request
(e.g. one of the two OSC 10/11 replies), the next ReadFile() blocks forever.

Wait with the same timeout before every subsequent ReadFile() as well, and
restore the console mode on that error path. While waiting, also skip
key-up records: ReadFile() returns no data for them, so one left alone in
the buffer would end the wait and the following ReadFile() would block.
@ihsandeniz

Copy link
Copy Markdown
Contributor Author

Fair point, a cut-off reply is the terminal's bug. Still, I don't think fastfetch should hang forever because of it: there's already a 1 s timeout before the first read, this only applies it to the following reads too.

It's also not limited to broken terminals. TerminalTheme sends OSC 10 and OSC 11 in one request and expects 6 values, so a terminal that answers OSC 10 but ignores OSC 11 leaves vsscanf at 3 and the next read() never returns. To be clear, I haven't hit this on a real terminal; I found it while looking into #2584 and reproduced it in a pty.

Added the Windows side as a second commit. The wait loop before the first ReadFile() is now a helper that also runs before each later ReadFile(), and the console mode is restored on that path. While waiting it also skips key-up records, since ReadFile() returns nothing for them and a leftover one would end the wait early. I cross-compiled it with mingw (zig cc) and tested under Wine by writing console input records: full and split replies still parse, a partial reply now returns after the timeout instead of hanging.

@CarterLi
CarterLi merged commit 2f68ce7 into fastfetch-cli:dev Oct 28, 2026
25 of 26 checks passed
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.

2 participants