]> granicus.if.org Git - vim/commitdiff
patch 8.2.3601: check for overflow in put count does not work well v8.2.3601
authorichizok <gclient.gaap@gmail.com>
Tue, 16 Nov 2021 12:50:46 +0000 (12:50 +0000)
committerBram Moolenaar <Bram@vim.org>
Tue, 16 Nov 2021 12:50:46 +0000 (12:50 +0000)
Problem:    Check for overflow in put count does not work well.
Solution:   Improve the overflow check. (Ozaki Kiichi, closes #9102)

src/register.c
src/testdir/test_put.vim
src/version.c

index 0afa363ecafe5237c5d3f338c9868e6e93aaaa70..129c80df810ae4aaddaf2d3236a7cab217c76d92 100644 (file)
@@ -1884,18 +1884,30 @@ do_put(
                    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 @@ do_put(
                    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_put(
                }
            }
 
-           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 @@ do_put(
                        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 @@ do_put(
                        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
index b2f212054e1ce0035b5e887f44f9466ddcc9baaa..8e9f3321b56ec23b9fd21db4c8c6acc236b38a31 100644 (file)
@@ -149,8 +149,16 @@ func Test_p_with_count_leaves_mark_at_end()
 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 @@ func Test_very_large_count()
   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'
index acc7a9b10fd6200134b1132540d4b87bc643fb20..3227bb605986b5d5d929dd5b13cebf4eb979eed6 100644 (file)
@@ -757,6 +757,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    3601,
 /**/
     3600,
 /**/