patch 8.0.1475: invalid memory access in read_redo()
Problem: Invalid memory access in read_redo(). (gy741)
Solution: Convert the replacement character back from a negative number to
CR or NL. (hint by Dominique Pelle, closes #2616)
diff --git a/src/normal.c b/src/normal.c
index 745a2f6..79e0b68 100644
--- a/src/normal.c
+++ b/src/normal.c
@@ -1685,11 +1685,19 @@
get_op_char(oap->op_type), get_extra_op_char(oap->op_type),
oap->motion_force, cap->cmdchar, cap->nchar);
else if (cap->cmdchar != ':')
+ {
+ int nchar = oap->op_type == OP_REPLACE ? cap->nchar : NUL;
+
+ /* reverse what nv_replace() did */
+ if (nchar == REPLACE_CR_NCHAR)
+ nchar = CAR;
+ else if (nchar == REPLACE_NL_NCHAR)
+ nchar = NL;
prep_redo(oap->regname, 0L, NUL, 'v',
get_op_char(oap->op_type),
get_extra_op_char(oap->op_type),
- oap->op_type == OP_REPLACE
- ? cap->nchar : NUL);
+ nchar);
+ }
if (!redo_VIsual_busy)
{
redo_VIsual_mode = resel_VIsual_mode;
@@ -7023,10 +7031,12 @@
reset_VIsual();
if (had_ctrl_v)
{
- if (cap->nchar == '\r')
- cap->nchar = -1;
- else if (cap->nchar == '\n')
- cap->nchar = -2;
+ /* Use a special (negative) number to make a difference between a
+ * literal CR or NL and a line break. */
+ if (cap->nchar == CAR)
+ cap->nchar = REPLACE_CR_NCHAR;
+ else if (cap->nchar == NL)
+ cap->nchar = REPLACE_NL_NCHAR;
}
nv_operator(cap);
return;
diff --git a/src/ops.c b/src/ops.c
index 83c36bd..1350d82 100644
--- a/src/ops.c
+++ b/src/ops.c
@@ -2113,13 +2113,21 @@
size_t oldlen;
struct block_def bd;
char_u *after_p = NULL;
- int had_ctrl_v_cr = (c == -1 || c == -2);
+ int had_ctrl_v_cr = FALSE;
if ((curbuf->b_ml.ml_flags & ML_EMPTY ) || oap->empty)
return OK; /* nothing to do */
- if (had_ctrl_v_cr)
- c = (c == -1 ? '\r' : '\n');
+ if (c == REPLACE_CR_NCHAR)
+ {
+ had_ctrl_v_cr = TRUE;
+ c = CAR;
+ }
+ else if (c == REPLACE_NL_NCHAR)
+ {
+ had_ctrl_v_cr = TRUE;
+ c = NL;
+ }
#ifdef FEAT_MBYTE
if (has_mbyte)
@@ -2207,7 +2215,8 @@
/* insert pre-spaces */
vim_memset(newp + bd.textcol, ' ', (size_t)bd.startspaces);
/* insert replacement chars CHECK FOR ALLOCATED SPACE */
- /* -1/-2 is used for entering CR literally. */
+ /* REPLACE_CR_NCHAR/REPLACE_NL_NCHAR is used for entering CR
+ * literally. */
if (had_ctrl_v_cr || (c != '\r' && c != '\n'))
{
#ifdef FEAT_MBYTE
@@ -6370,7 +6379,7 @@
* |{bartype},{flags},{name},{type},
* {linecount},{width},{timestamp},"line1","line2"
* flags: REG_PREVIOUS - register is y_previous
- * REG_EXEC - used for @@
+ * REG_EXEC - used for @@
*/
if (y_previous == &y_regs[i])
flags |= REG_PREVIOUS;
diff --git a/src/testdir/test_undo.vim b/src/testdir/test_undo.vim
index cc3cceb..c1b821e 100644
--- a/src/testdir/test_undo.vim
+++ b/src/testdir/test_undo.vim
@@ -403,3 +403,10 @@
bwipe!
endfunc
+
+func Test_redo_empty_line()
+ new
+ exe "norm\x16r\x160"
+ exe "norm."
+ bwipe!
+endfunc
diff --git a/src/version.c b/src/version.c
index 350c830..98a9132 100644
--- a/src/version.c
+++ b/src/version.c
@@ -772,6 +772,8 @@
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 1475,
+/**/
1474,
/**/
1473,
diff --git a/src/vim.h b/src/vim.h
index ad37235..bd8ac08 100644
--- a/src/vim.h
+++ b/src/vim.h
@@ -2515,4 +2515,8 @@
# endif
#endif
+/* Replacement for nchar used by nv_replace(). */
+#define REPLACE_CR_NCHAR -1
+#define REPLACE_NL_NCHAR -2
+
#endif /* VIM__H */