csi: refactor CHT/CBT

Eliminate the outer loop, so that when moving the cursor multiple
tab stops, we no longer iterate the tab stop list all over again.

This also fixes a DoS flaw when passing a very large value as
CHT/CBT argument, which may hang the terminal.

Closes #2360
This commit is contained in:
CismonX 2026-05-25 06:31:04 +08:00 committed by Daniel Eklöf
parent 382e9a31c5
commit 66ec9fad88
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
2 changed files with 24 additions and 18 deletions

View file

@ -94,11 +94,14 @@
`meson.build` ([#2379][2379]). `meson.build` ([#2379][2379]).
* Block selection area incorrectly updated when selecting back * Block selection area incorrectly updated when selecting back
across the starting column. across the starting column.
* Passing a very large value as CHT/CBT argument hangs the terminal
([#2360][2360]).
[2353]: https://codeberg.org/dnkl/foot/issues/2353 [2353]: https://codeberg.org/dnkl/foot/issues/2353
[2352]: https://codeberg.org/dnkl/foot/issues/2352 [2352]: https://codeberg.org/dnkl/foot/issues/2352
[2327]: https://codeberg.org/dnkl/foot/issues/2327 [2327]: https://codeberg.org/dnkl/foot/issues/2327
[2379]: https://codeberg.org/dnkl/foot/issues/2379 [2379]: https://codeberg.org/dnkl/foot/issues/2379
[2360]: https://codeberg.org/dnkl/foot/issues/2360
### Security ### Security

39
csi.c
View file

@ -1171,37 +1171,40 @@ csi_dispatch(struct terminal *term, uint8_t final)
case 'I': { case 'I': {
/* CHT - Tab Forward (param is number of tab stops to move through) */ /* CHT - Tab Forward (param is number of tab stops to move through) */
for (int i = 0; i < vt_param_get(term, 0, 1); i++) { int count = vt_param_get(term, 0, 1);
int new_col = term->cols - 1; int new_col = term->grid->cursor.point.col;
tll_foreach(term->tab_stops, it) { tll_foreach(term->tab_stops, it) {
if (it->item > term->grid->cursor.point.col) { if (it->item > new_col) {
new_col = it->item; if (--count < 0) {
break; break;
} }
new_col = it->item;
} }
xassert(new_col >= term->grid->cursor.point.col);
bool lcf = term->grid->cursor.lcf;
term_cursor_right(term, new_col - term->grid->cursor.point.col);
term->grid->cursor.lcf = lcf;
} }
xassert(new_col >= term->grid->cursor.point.col);
bool lcf = term->grid->cursor.lcf;
term_cursor_right(term, new_col - term->grid->cursor.point.col);
term->grid->cursor.lcf = lcf;
break; break;
} }
case 'Z': case 'Z': {
/* CBT - Back tab (param is number of tab stops to move back through) */ /* CBT - Back tab (param is number of tab stops to move back through) */
for (int i = 0; i < vt_param_get(term, 0, 1); i++) { int count = vt_param_get(term, 0, 1);
int new_col = 0; int new_col = term->grid->cursor.point.col;
tll_rforeach(term->tab_stops, it) { tll_rforeach(term->tab_stops, it) {
if (it->item < term->grid->cursor.point.col) { if (it->item < new_col) {
new_col = it->item; if (--count < 0) {
break; break;
} }
new_col = it->item;
} }
xassert(term->grid->cursor.point.col >= new_col);
term_cursor_left(term, term->grid->cursor.point.col - new_col);
} }
xassert(term->grid->cursor.point.col >= new_col);
term_cursor_left(term, term->grid->cursor.point.col - new_col);
break; break;
}
case 'h': case 'h':
case 'l': { case 'l': {