patch 8.2.3601: check for overflow in put count does not work well

Problem:    Check for overflow in put count does not work well.
Solution:   Improve the overflow check. (Ozaki Kiichi, closes #9102)
diff --git a/src/register.c b/src/register.c
index 0afa363..129c80d 100644
--- a/src/register.c
+++ b/src/register.c
@@ -1884,18 +1884,30 @@
 		    spaces = 0;
 	    }
 
-	    // insert the new text
+	    // Insert the new text.
+	    // First check for multiplication overflow.
+	    if (yanklen + spaces != 0
+		     && count > ((INT_MAX - (bd.startspaces + bd.endspaces))
+							/ (yanklen + spaces)))
+	    {
+		emsg(_(e_resulting_text_too_long));
+		break;
+	    }
+
 	    totlen = count * (yanklen + spaces) + bd.startspaces + bd.endspaces;
 	    newp = alloc(totlen + oldlen + 1);
 	    if (newp == NULL)
 		break;
+
 	    // copy part up to cursor to new line
 	    ptr = newp;
 	    mch_memmove(ptr, oldp, (size_t)bd.textcol);
 	    ptr += bd.textcol;
+
 	    // may insert some spaces before the new text
 	    vim_memset(ptr, ' ', (size_t)bd.startspaces);
 	    ptr += bd.startspaces;
+
 	    // insert the new text
 	    for (j = 0; j < count; ++j)
 	    {
@@ -1909,9 +1921,11 @@
 		    ptr += spaces;
 		}
 	    }
+
 	    // may insert some spaces after the new text
 	    vim_memset(ptr, ' ', (size_t)bd.endspaces);
 	    ptr += bd.endspaces;
+
 	    // move the text after the cursor to the end of the line.
 	    mch_memmove(ptr, oldp + bd.textcol + delcount,
 				(size_t)(oldlen - bd.textcol - delcount + 1));
@@ -2010,26 +2024,20 @@
 		}
 	    }
 
-	    do {
-#ifdef FEAT_FLOAT
-		double multlen = (double)count * (double)yanklen;
-
+	    if (count == 0 || yanklen == 0)
+	    {
+		if (VIsual_active)
+		    lnum = end_lnum;
+	    }
+	    else if (count > INT_MAX / yanklen)
+		// multiplication overflow
+		emsg(_(e_resulting_text_too_long));
+	    else
+	    {
 		totlen = count * yanklen;
-		if ((double)totlen != multlen)
-#else
-		long multlen = count * yanklen;
-
-		// this only works when sizeof(int) != sizeof(long)
-		totlen = multlen;
-		if (totlen != multlen)
-#endif
-		{
-		    emsg(_(e_resulting_text_too_long));
-		    break;
-		}
-		else if (totlen > 0)
-		{
+		do {
 		    oldp = ml_get(lnum);
+		    oldlen = (int)STRLEN(oldp);
 		    if (lnum > start_lnum)
 		    {
 			pos_T   pos;
@@ -2040,12 +2048,12 @@
 			else
 			    col = MAXCOL;
 		    }
-		    if (VIsual_active && col > (int)STRLEN(oldp))
+		    if (VIsual_active && col > oldlen)
 		    {
 			lnum++;
 			continue;
 		    }
-		    newp = alloc(STRLEN(oldp) + totlen + 1);
+		    newp = alloc(totlen + oldlen + 1);
 		    if (newp == NULL)
 			goto end;	// alloc() gave an error message
 		    mch_memmove(newp, oldp, (size_t)col);
@@ -2064,13 +2072,13 @@
 			changed_cline_bef_curs();
 			curwin->w_cursor.col += (colnr_T)(totlen - 1);
 		    }
-		}
-		if (VIsual_active)
-		    lnum++;
-	    } while (VIsual_active && lnum <= end_lnum);
+		    if (VIsual_active)
+			lnum++;
+		} while (VIsual_active && lnum <= end_lnum);
 
-	    if (VIsual_active) // reset lnum to the last visual line
-		lnum--;
+		if (VIsual_active) // reset lnum to the last visual line
+		    lnum--;
+	    }
 
 	    curbuf->b_op_end = curwin->w_cursor;
 	    // For "CTRL-O p" in Insert mode, put cursor after last char
diff --git a/src/testdir/test_put.vim b/src/testdir/test_put.vim
index b2f2120..8e9f332 100644
--- a/src/testdir/test_put.vim
+++ b/src/testdir/test_put.vim
@@ -149,8 +149,16 @@
 endfunc
 
 func Test_very_large_count()
-  if v:sizeofint != 8
-    throw 'Skipped: only works with 64 bit ints'
+  new
+  " total put-length (21474837 * 100) brings 32 bit int overflow
+  let @" = repeat('x', 100)
+  call assert_fails('norm 21474837p', 'E1240:')
+  bwipe!
+endfunc
+
+func Test_very_large_count_64bit()
+  if v:sizeoflong < 8
+    throw 'Skipped: only works with 64 bit long ints'
   endif
 
   new
@@ -159,6 +167,27 @@
   bwipe!
 endfunc
 
+func Test_very_large_count_block()
+  new
+  " total put-length (21474837 * 100) brings 32 bit int overflow
+  call setline(1, repeat('x', 100))
+  exe "norm \<C-V>99ly"
+  call assert_fails('norm 21474837p', 'E1240:')
+  bwipe!
+endfunc
+
+func Test_very_large_count_block_64bit()
+  if v:sizeoflong < 8
+    throw 'Skipped: only works with 64 bit long ints'
+  endif
+
+  new
+  call setline(1, 'x')
+  exe "norm \<C-V>y"
+  call assert_fails('norm 44444444444444p', 'E1240:')
+  bwipe!
+endfunc
+
 func Test_put_above_first_line()
   new
   let @" = 'text'
diff --git a/src/version.c b/src/version.c
index acc7a9b..3227bb6 100644
--- a/src/version.c
+++ b/src/version.c
@@ -758,6 +758,8 @@
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    3601,
+/**/
     3600,
 /**/
     3599,