From 9f82cbaa496f3c9c8210d3e78bee0de038d232e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sat, 25 Jul 2020 11:23:54 +0200 Subject: [PATCH] search: fix crash when searching the scrollback history search_update_selection() was changed in 1.4.x to *first* update the selection, *then* move the viewport. This leads to a crash if the new match (selection) is outside the current viewport; the selection code assumes the updated selection endpoint is in the visible viewport. Changing back to *first* move the viewport, *then* update the selection solves this. --- CHANGELOG.md | 4 +++ search.c | 100 ++++++++++++++++++++++++++------------------------- 2 files changed, 56 insertions(+), 48 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a6c93071..171765d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,6 +40,10 @@ ### Deprecated ### Removed ### Fixed + +* Crash in scrollback search + + ### Security diff --git a/search.c b/search.c index e02aaa7c..a0b87a13 100644 --- a/search.c +++ b/search.c @@ -104,6 +104,58 @@ search_update_selection(struct terminal *term, int start_row, int start_col, int end_row, int end_col) { + bool move_viewport = true; + + int view_end = (term->grid->view + term->rows - 1) & (term->grid->num_rows - 1); + if (view_end >= term->grid->view) { + /* Viewport does *not* wrap around */ + if (start_row >= term->grid->view && end_row <= view_end) + move_viewport = false; + } else { + /* Viewport wraps */ + if (start_row >= term->grid->view || end_row <= view_end) + move_viewport = false; + } + + if (move_viewport) { + int old_view = term->grid->view; + int new_view = start_row - term->rows / 2; + + while (new_view < 0) + new_view += term->grid->num_rows; + + /* Prevent scrolling in uninitialized rows */ + bool all_initialized = false; + do { + all_initialized = true; + + for (int i = 0; i < term->rows; i++) { + int row_no = (new_view + i) % term->grid->num_rows; + if (term->grid->rows[row_no] == NULL) { + all_initialized = false; + new_view--; + break; + } + } + } while (!all_initialized); + + /* Don't scroll past scrollback history */ + int end = (term->grid->offset + term->rows - 1) % term->grid->num_rows; + if (end >= term->grid->offset) { + /* Not wrapped */ + if (new_view >= term->grid->offset && new_view <= end) + new_view = term->grid->offset; + } else { + if (new_view >= term->grid->offset || new_view <= end) + new_view = term->grid->offset; + } + + /* Update view */ + term->grid->view = new_view; + if (new_view != old_view) + term_damage_view(term); + } + /* Selection endpoint is inclusive */ if (--end_col < 0) { end_col = term->cols - 1; @@ -133,54 +185,6 @@ search_update_selection(struct terminal *term, selection_row < term->grid->num_rows); selection_update(term, end_col, selection_row); } - - int view_end = (term->grid->view + term->rows - 1) & (term->grid->num_rows - 1); - if (view_end >= term->grid->view) { - /* Viewport does *not* wrap around */ - if (start_row >= term->grid->view && end_row <= view_end) - return; - } else { - /* Viewport wraps */ - if (start_row >= term->grid->view || end_row <= view_end) - return; - } - - int old_view = term->grid->view; - int new_view = start_row - term->rows / 2; - - while (new_view < 0) - new_view += term->grid->num_rows; - - /* Prevent scrolling in uninitialized rows */ - bool all_initialized = false; - do { - all_initialized = true; - - for (int i = 0; i < term->rows; i++) { - int row_no = (new_view + i) % term->grid->num_rows; - if (term->grid->rows[row_no] == NULL) { - all_initialized = false; - new_view--; - break; - } - } - } while (!all_initialized); - - /* Don't scroll past scrollback history */ - int end = (term->grid->offset + term->rows - 1) % term->grid->num_rows; - if (end >= term->grid->offset) { - /* Not wrapped */ - if (new_view >= term->grid->offset && new_view <= end) - new_view = term->grid->offset; - } else { - if (new_view >= term->grid->offset || new_view <= end) - new_view = term->grid->offset; - } - - /* Update view */ - term->grid->view = new_view; - if (new_view != old_view) - term_damage_view(term); } static void