PuTTY bug resize-delay

Home | FAQ | Feedback | Licence | Updates | Mirrors | Keys | Links | Team
Download: Stable · Snapshot | Docs | Changes | Wishlist

summary: Delayed semantic effect of terminal resizing escape sequences
class: bug: This is clearly an actual problem we want fixed.
difficulty: tricky: Needs many tuits.
priority: medium: This should be fixed one day.
absent-in: 0.74 99dfc66457d19f0769a0b5cfe9dd7f924e22ee71
present-in: 0.75 d74308e90e3813af664f91ef8c9d1a0644aa9544
fixed-in: 420fe75552afa9490c7ca2ff08e92ec96933cfe1 (0.77)

When the PuTTY terminal code wants to make a change to the terminal window properties, the change is not made immediately, but queued until the next window redraw. This policy was introduced as a means of limiting the rate at which a server could cause PuTTY to perform GUI activity, preventing at least one server-triggerable DoS attack.

One of the window-property changes included in this policy is its size. When the server sends any of the escape sequences that triggers a terminal resize (including both the DECCOLM ESC[?3h / ESC[?3l sequences for 80/132 column switch, and the xterm general resize sequence ESC[8;H;Wt), the actual resize may not happen until up to 20ms later.

But it's not unreasonable for the server to send a control sequence to resize the terminal, and then immediately follow that up with a stream of terminal output that draws a full screen of text in the expectation that it's drawing on the new window size. So if PuTTY has not yet enacted the size change, then that redraw can go wrong, e.g. with lines of text intended for the new terminal width wrapping at the shorter old width. (Or being truncated, depending on other terminal settings, but neither of those was what you actually wanted.)

It's not clear what the best fix for this might be. I can think of several plausible options:

Revert the rate-limiting for resizes, and put things back to the way they used to work, so that window resizes are enacted synchronously. That might be OK: we don't know for sure that a significant server-triggered DoS is available relating to resizes in particular. But it might reintroduce a vulnerability, so I'd rather not do it that way.

Pause processing of terminal output until a resize completes. The physical window resize would still happen at the same time as it currently does, but until it was finished, terminal output would remain in terminal.c's incoming buffer, waiting for the terminal to be the right size to accept it. This would introduce up to 20ms of delay in terminal output processing whenever a resize took place.

Decouple logical and physical terminal resizes. Perhaps the most conceptually clean solution, but also the trickiest to implement: respond to a terminal resize request by immediately changing the logical size of the terminal screen in the terminal.c data structures, so that further terminal data can be immediately processed and will find terminal features like line wrapping behaving as expected. But the physical resize of the window, in the GUI, would still wait until the next redraw timer, and at that point, the window would become the new size and have the new contents drawn on it.

The biggest problem with this last option is: what happens if the GUI doesn't give us the window size we asked for? If you try to resize a window larger than the screen on some GUI platforms (including Windows), you get a size that will fit in place of the size you requested. And you don't find this out until you actually attempt the physical resize in the GUI, and get sent a WM_SIZE telling you what size you actually got. So in the decoupled approach, you'd end up already having drawn a load of output to the terminal data structures in the expectation of getting one size, and by the time you find you got a different size instead, it's a bit late to figure out what the screen should have ended up looking like.

But perhaps that doesn't matter too much, and we should just regard that later change of mind on the GUI's part as equivalent to a user action resizing the terminal window. It's not clear.

2021-12-29: should be fixed by 420fe75552afa9490c7ca2ff08e92ec96933cfe1, using the middle option of the three listed above: we pause output processing while waiting for the window system to respond to our resize and tell us what size we ended up with. This does cause a bit of delay, because we still enact the window resize on a timer, so you can start with up to 20ms of delay while waiting for that timer to fire, and then it might take time to get a response back from the window system (e.g. if it's X11 and everything is asynchronous).

A danger on X11 in particular is that if the window manager is in a confused state, it might never get round to responding to the resize request, even to send a notification that it refused. There's a fallback 5-second timeout for that situation, to avoid terminal output processing being 'paused' forever.

If you want to comment on this web site, see the Feedback page.
Audit trail for this bug.
(last revision of this bug record was at 2021-12-29 16:30:25 +0000)