search: fix infinite loop when highlighting all matches

find_next() did not always terminate correctly, causing
search_matches_next() to never terminate, which finally leads to an
infinite loop when rendering the search overlay surface, while finding
all matches to highlight.

The problem is that find_next(), after having found the initial
matching characters, enters a nested while loop that tries to match
the rest of the search criteria. This inner while loop did not check
if we’ve reached the last cell, and happily continued past
it (eventually wrappping around the scrollback buffer).

Closes #1047
This commit is contained in:
Daniel Eklöf 2022-04-26 18:24:22 +02:00
parent 694938b85b
commit 0e9ebf433b
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
2 changed files with 16 additions and 1 deletions

View file

@ -58,7 +58,8 @@
* UI not refreshing when pasting something into the scrollback search
box, that does not result in a grid update (for example, when the
search criteria did not result in any matches) ([#1040][1040]).
* foot freezing in scrollback search mode, using 100% CPU ([#1036][1036]).
* foot freezing in scrollback search mode, using 100% CPU
([#1036][1036], [#1047][1047]).
* Crash when extending a selection to the next word boundary in
scrollback search mode ([#1036][1036]).
* Scrollback search mode not always highlighting all matches
@ -66,6 +67,7 @@
[1040]: https://codeberg.org/dnkl/foot/issues/1040
[1036]: https://codeberg.org/dnkl/foot/issues/1036
[1047]: https://codeberg.org/dnkl/foot/issues/1036
### Security

View file

@ -375,6 +375,13 @@ find_next(struct terminal *term, enum search_direction direction,
if (match_len != term->search.len) {
/* Didn't match (completely) */
if (match_start_row == abs_end.row &&
match_start_col == abs_end.col)
{
break;
}
continue;
}
@ -563,10 +570,16 @@ search_matches_next(struct search_match_iterator *iter)
xassert(match.end.row >= 0);
xassert(match.end.row < term->rows);
/* Assert match end comes *after* the match start */
xassert(match.end.row > match.start.row ||
(match.end.row == match.start.row &&
match.end.col >= match.start.col));
/* Assert the match starts at, or after, the iterator position */
xassert(match.start.row > iter->start.row ||
(match.start.row == iter->start.row &&
match.start.col >= iter->start.col));
/* Continue at next column, next time */
iter->start.row = match.start.row;
iter->start.col = match.start.col + 1;