diff --git a/src/nvim/mouse.c b/src/nvim/mouse.c index 9c6acf9f80..aca15eb0e2 100644 --- a/src/nvim/mouse.c +++ b/src/nvim/mouse.c @@ -1692,7 +1692,8 @@ static int mouse_adjust_click(win_T *wp, int row, int col) // highlighting the second byte, not the ninth. linenr_T lnum = wp->w_cursor.lnum; - char *line = ml_get(lnum); + // Make a copy of the line, because syntax matching may free it. + char *line = xstrdup(ml_get(lnum)); char *ptr = line; char *ptr_end; char *ptr_row_offset = line; // Where we begin adjusting `ptr_end` @@ -1733,8 +1734,8 @@ static int mouse_adjust_click(win_T *wp, int row, int col) vcol = offset; -#define INCR() nudge++; ptr_end += utfc_ptr2len((char *)ptr_end) -#define DECR() nudge--; ptr_end -= utfc_ptr2len((char *)ptr_end) +#define INCR() nudge++; ptr_end += utfc_ptr2len(ptr_end) +#define DECR() nudge--; ptr_end -= utfc_ptr2len(ptr_end) while (ptr < ptr_end && *ptr != NUL) { int cwidth = win_chartabsize(curwin, ptr, vcol); @@ -1776,6 +1777,7 @@ static int mouse_adjust_click(win_T *wp, int row, int col) ptr += utfc_ptr2len(ptr); } + xfree(line); return col + nudge; } diff --git a/test/functional/ui/mouse_spec.lua b/test/functional/ui/mouse_spec.lua index d8739e1c31..621855f051 100644 --- a/test/functional/ui/mouse_spec.lua +++ b/test/functional/ui/mouse_spec.lua @@ -1024,13 +1024,15 @@ describe('ui/mouse/input', function() }) feed('ggdG') - feed_command('set concealcursor=ni') - feed_command('set nowrap') - feed_command('set shiftwidth=2 tabstop=4 list') - feed_command('setl listchars=tab:>-') - feed_command('syntax match NonText "\\*" conceal') - feed_command('syntax match NonText "cats" conceal cchar=X') - feed_command('syntax match NonText "x" conceal cchar=>') + command([[setlocal concealcursor=ni nowrap shiftwidth=2 tabstop=4 list listchars=tab:>-]]) + command([[syntax region X0 matchgroup=X1 start=/\*/ end=/\*/ concealends contains=X2]]) + command([[syntax match X2 /cats/ conceal cchar=X contained]]) + -- No heap-use-after-free with multi-line syntax pattern #24317 + command([[syntax match X3 /\n\@<=x/ conceal cchar=>]]) + command([[highlight link X0 Normal]]) + command([[highlight link X1 NonText]]) + command([[highlight link X2 NonText]]) + command([[highlight link X3 NonText]]) -- First column is there to retain the tabs. insert([[