Skip to content

Commit

Permalink
Fix fullwidth char regex search infinite loop
Browse files Browse the repository at this point in the history
This resolves an issue where the regex search could loop indefinitely
when the end point was defined in a location containing a fullwidth
character, thus skipping over the end before termination.

Fixes alacritty#5753.
  • Loading branch information
chrisduerr committed Jan 8, 2022
1 parent 5aa8046 commit ed35d03
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Freeze when the vi cursor is on the scrollback and scrollback clear is invoked
- Vi cursor on topmost of the display moving downward when scrolled into history with active output
- Input lag on Wayland with Nvidia binary driver
- Crash when hovering the mouse over fullwidth characters

### Removed

Expand Down
28 changes: 27 additions & 1 deletion alacritty_terminal/src/term/search.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@ impl<T> Term<T> {
let mut state = dfa.start_state();
let mut last_wrapped = false;
let mut regex_match = None;
let mut done = false;

let mut cell = iter.cell();
self.skip_fullwidth(&mut iter, &mut cell, direction);
Expand Down Expand Up @@ -239,7 +240,7 @@ impl<T> Term<T> {
}

// Stop once we've reached the target point.
if point == end {
if point == end || done {
break;
}

Expand All @@ -254,7 +255,12 @@ impl<T> Term<T> {
iter.cell()
},
};

// Check for completion before potentially skipping over fullwidth characters.
done = iter.point() == end;

self.skip_fullwidth(&mut iter, &mut cell, direction);

let wrapped = cell.flags.contains(Flags::WRAPLINE);
c = cell.c;

Expand Down Expand Up @@ -700,6 +706,26 @@ mod tests {
assert_eq!(term.regex_search_left(&dfas, start, end), Some(end..=start));
}

#[test]
fn end_on_fullwidth() {
let term = mock_term("jarr🦇");

let start = Point::new(Line(0), Column(0));
let end = Point::new(Line(0), Column(4));

// Ensure ending without a match doesn't loop indefinitely.
let dfas = RegexSearch::new("x").unwrap();
assert_eq!(term.regex_search_right(&dfas, start, end), None);

let dfas = RegexSearch::new("x").unwrap();
let match_end = Point::new(Line(0), Column(5));
assert_eq!(term.regex_search_right(&dfas, start, match_end), None);

// Ensure match is captured when only partially inside range.
let dfas = RegexSearch::new("jarr🦇").unwrap();
assert_eq!(term.regex_search_right(&dfas, start, end), Some(start..=match_end));
}

#[test]
fn wrapping() {
#[rustfmt::skip]
Expand Down

0 comments on commit ed35d03

Please sign in to comment.