aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/nvim/mark.c6
-rw-r--r--src/nvim/mbyte.c4
-rw-r--r--src/nvim/testdir/test_undo.vim9
3 files changed, 17 insertions, 2 deletions
diff --git a/src/nvim/mark.c b/src/nvim/mark.c
index b9c91de2a8..3861d9ceb8 100644
--- a/src/nvim/mark.c
+++ b/src/nvim/mark.c
@@ -1465,7 +1465,11 @@ void mark_mb_adjustpos(buf_T *buf, pos_T *lp)
{
if (lp->col > 0 || lp->coladd > 1) {
const char_u *const p = ml_get_buf(buf, lp->lnum, false);
- lp->col -= (*mb_head_off)(p, p + lp->col);
+ if (*p == NUL || (int)STRLEN(p) < lp->col) {
+ lp->col = 0;
+ } else {
+ lp->col -= (*mb_head_off)(p, p + lp->col);
+ }
// Reset "coladd" when the cursor would be on the right half of a
// double-wide character.
if (lp->coladd == 1
diff --git a/src/nvim/mbyte.c b/src/nvim/mbyte.c
index 7c196831ba..15fe51cad1 100644
--- a/src/nvim/mbyte.c
+++ b/src/nvim/mbyte.c
@@ -566,7 +566,9 @@ int utf_off2cells(unsigned off, unsigned max_off)
/// Convert a UTF-8 byte sequence to a wide character
///
/// If the sequence is illegal or truncated by a NUL then the first byte is
-/// returned. Does not include composing characters for obvious reasons.
+/// returned.
+/// For an overlong sequence this may return zero.
+/// Does not include composing characters for obvious reasons.
///
/// @param[in] p String to convert.
///
diff --git a/src/nvim/testdir/test_undo.vim b/src/nvim/testdir/test_undo.vim
index 38610f8002..3e6e276751 100644
--- a/src/nvim/testdir/test_undo.vim
+++ b/src/nvim/testdir/test_undo.vim
@@ -348,3 +348,12 @@ func Test_redo_empty_line()
exe "norm."
bwipe!
endfunc
+
+" This used to cause an illegal memory access
+func Test_undo_append()
+ new
+ call feedkeys("axx\<Esc>v", 'xt')
+ undo
+ norm o
+ quit
+endfunc