Blame SOURCES/0001-patch-8.2.4120-block-insert-goes-over-the-end-of-the.patch

9bb4fd
diff -up vim80/src/ops.c.cve0261 vim80/src/ops.c
9bb4fd
--- vim80/src/ops.c.cve0261	2022-01-26 14:30:27.475308323 +0100
9bb4fd
+++ vim80/src/ops.c	2022-01-26 14:34:16.650933713 +0100
9bb4fd
@@ -636,23 +636,30 @@ block_insert(
9bb4fd
 	    if (b_insert)
9bb4fd
 	    {
9bb4fd
 		off = (*mb_head_off)(oldp, oldp + offset + spaces);
9bb4fd
+		spaces -= off;
9bb4fd
+		count -= off;
9bb4fd
 	    }
9bb4fd
 	    else
9bb4fd
 	    {
9bb4fd
-		off = (*mb_off_next)(oldp, oldp + offset);
9bb4fd
-		offset += off;
9bb4fd
+		// spaces fill the gap, the character that's at the edge moves
9bb4fd
+		// right
9bb4fd
+		off = (*mb_head_off)(oldp, oldp + offset);
9bb4fd
+		offset -= off;
9bb4fd
 	    }
9bb4fd
 	    spaces -= off;
9bb4fd
 	    count -= off;
9bb4fd
 	}
9bb4fd
 #endif
9bb4fd
 
9bb4fd
-	newp = alloc_check((unsigned)(STRLEN(oldp)) + s_len + count + 1);
9bb4fd
+	// Make sure the allocated size matches what is actually copied below.
9bb4fd
+	newp = alloc(STRLEN(oldp) + spaces + s_len
9bb4fd
+		    + (spaces > 0 && !bdp->is_short ? p_ts - spaces : 0)
9bb4fd
+								  + count + 1);
9bb4fd
 	if (newp == NULL)
9bb4fd
 	    continue;
9bb4fd
 
9bb4fd
 	/* copy up to shifted part */
9bb4fd
-	mch_memmove(newp, oldp, (size_t)(offset));
9bb4fd
+	mch_memmove(newp, oldp, (size_t)offset);
9bb4fd
 	oldp += offset;
9bb4fd
 
9bb4fd
 	/* insert pre-padding */
9bb4fd
@@ -662,14 +669,21 @@ block_insert(
9bb4fd
 	mch_memmove(newp + offset + spaces, s, (size_t)s_len);
9bb4fd
 	offset += s_len;
9bb4fd
 
9bb4fd
-	if (spaces && !bdp->is_short)
9bb4fd
+	if (spaces > 0 && !bdp->is_short)
9bb4fd
 	{
9bb4fd
-	    /* insert post-padding */
9bb4fd
-	    vim_memset(newp + offset + spaces, ' ', (size_t)(p_ts - spaces));
9bb4fd
-	    /* We're splitting a TAB, don't copy it. */
9bb4fd
-	    oldp++;
9bb4fd
-	    /* We allowed for that TAB, remember this now */
9bb4fd
-	    count++;
9bb4fd
+	    if (*oldp == TAB)
9bb4fd
+	    {
9bb4fd
+		// insert post-padding
9bb4fd
+		vim_memset(newp + offset + spaces, ' ',
9bb4fd
+						    (size_t)(p_ts - spaces));
9bb4fd
+		// we're splitting a TAB, don't copy it
9bb4fd
+		oldp++;
9bb4fd
+		// We allowed for that TAB, remember this now
9bb4fd
+		count++;
9bb4fd
+	    }
9bb4fd
+	    else
9bb4fd
+		// Not a TAB, no extra spaces
9bb4fd
+		count = spaces;
9bb4fd
 	}
9bb4fd
 
9bb4fd
 	if (spaces > 0)
9bb4fd
@@ -2738,9 +2752,9 @@ op_insert(oparg_T *oap, long count1)
9bb4fd
 		oap->start_vcol = t;
9bb4fd
 	    }
9bb4fd
 	    else if (oap->op_type == OP_APPEND
9bb4fd
-		      && oap->end.col
9bb4fd
+		      && oap->start.col
9bb4fd
 #ifdef FEAT_VIRTUALEDIT
9bb4fd
-			    + oap->end.coladd
9bb4fd
+			    + oap->start.coladd
9bb4fd
 #endif
9bb4fd
 			>= curbuf->b_op_start_orig.col
9bb4fd
 #ifdef FEAT_VIRTUALEDIT
9bb4fd
diff -up vim80/src/testdir/test_visual.vim.cve0261 vim80/src/testdir/test_visual.vim
9bb4fd
--- vim80/src/testdir/test_visual.vim.cve0261	2022-01-26 14:30:27.476308325 +0100
9bb4fd
+++ vim80/src/testdir/test_visual.vim	2022-01-26 14:36:03.482225225 +0100
9bb4fd
@@ -254,3 +254,12 @@ func Test_virtual_replace2()
9bb4fd
   %d_
9bb4fd
   set bs&vim
9bb4fd
 endfunc
9bb4fd
+
9bb4fd
+func Test_visual_block_append_invalid_char()
9bb4fd
+  " this was going over the end of the line
9bb4fd
+  new
9bb4fd
+  call setline(1, ['	   let xxx', 'xxxxxˆ', 'xxxxxxxxxxx'])
9bb4fd
+  exe "normal 0\<C-V>jjA-\<Esc>"
9bb4fd
+  call assert_equal(['	-   let xxx', 'xxxxx   -ˆ', 'xxxxxxxx-xxx'], getline(1, 3))
9bb4fd
+  bwipe!
9bb4fd
+endfunc