changeset 26256:92fbed13ca4d v8.2.3659

patch 8.2.3659: integer overflow with large line number Commit: https://github.com/vim/vim/commit/03725c5795ae5b8c14da4a39cd0ce723c6dd4304 Author: Bram Moolenaar <Bram@vim.org> Date: Wed Nov 24 12:17:53 2021 +0000 patch 8.2.3659: integer overflow with large line number Problem: Integer overflow with large line number. Solution: Check for overflow. (closes https://github.com/vim/vim/issues/9202)
author Bram Moolenaar <Bram@vim.org>
date Wed, 24 Nov 2021 13:30:03 +0100
parents c69a537bd421
children e3534fa157a0
files src/errors.h src/ex_docmd.c src/normal.c src/testdir/test_excmd.vim src/testdir/test_normal.vim src/version.c
diffstat 6 files changed, 64 insertions(+), 6 deletions(-) [+]
line wrap: on
line diff
--- a/src/errors.h
+++ b/src/errors.h
@@ -688,3 +688,5 @@ EXTERN char e_cannot_expand_sfile_in_vim
 	INIT(= N_("E1245: Cannot expand <sfile> in a Vim9 function"));
 EXTERN char e_cannot_find_variable_to_unlock_str[]
 	INIT(= N_("E1246: Cannot find variable to (un)lock: %s"));
+EXTERN char e_line_number_out_of_range[]
+	INIT(= N_("E1247: Line number out of range"));
--- a/src/ex_docmd.c
+++ b/src/ex_docmd.c
@@ -4380,7 +4380,14 @@ get_address(
 	    if (!VIM_ISDIGIT(*cmd))	// '+' is '+1', but '+0' is not '+1'
 		n = 1;
 	    else
+	    {
 		n = getdigits(&cmd);
+		if (n == MAXLNUM)
+		{
+		    emsg(_(e_line_number_out_of_range));
+		    goto error;
+		}
+	    }
 
 	    if (addr_type == ADDR_TABS_RELATIVE)
 	    {
@@ -4398,13 +4405,20 @@ get_address(
 		// Relative line addressing, need to adjust for folded lines
 		// now, but only do it after the first address.
 		if (addr_type == ADDR_LINES && (i == '-' || i == '+')
-			&& address_count >= 2)
+							 && address_count >= 2)
 		    (void)hasFolding(lnum, NULL, &lnum);
 #endif
 		if (i == '-')
 		    lnum -= n;
 		else
+		{
+		    if (n >= LONG_MAX - lnum)
+		    {
+			emsg(_(e_line_number_out_of_range));
+			goto error;
+		    }
 		    lnum += n;
+		}
 	    }
 	}
     } while (*cmd == '/' || *cmd == '?');
--- a/src/normal.c
+++ b/src/normal.c
@@ -630,10 +630,14 @@ getcount:
 		del_from_showcmd(4);	// delete the digit and ~@%
 #endif
 	    }
+	    else if (ca.count0 >= 999999999L)
+	    {
+		ca.count0 = 999999999L;
+	    }
 	    else
+	    {
 		ca.count0 = ca.count0 * 10 + (c - '0');
-	    if (ca.count0 < 0)	    // overflow
-		ca.count0 = 999999999L;
+	    }
 #ifdef FEAT_EVAL
 	    // Set v:count here, when called from main() and not a stuffed
 	    // command, so that v:count can be used in an expression mapping
@@ -700,11 +704,14 @@ getcount:
 	 * multiplied.
 	 */
 	if (ca.count0)
-	    ca.count0 *= ca.opcount;
+	{
+	    if (ca.opcount >= 999999999L / ca.count0)
+		ca.count0 = 999999999L;
+	    else
+		ca.count0 *= ca.opcount;
+	}
 	else
 	    ca.count0 = ca.opcount;
-	if (ca.count0 < 0)	    // overflow
-	    ca.count0 = 999999999L;
     }
 
     /*
--- a/src/testdir/test_excmd.vim
+++ b/src/testdir/test_excmd.vim
@@ -655,4 +655,16 @@ func Test_not_break_expression_register(
   call assert_equal('1+1', getreg('=', 1))
 endfunc
 
+func Test_address_line_overflow()
+  if v:sizeoflong < 8
+    throw 'Skipped: only works with 64 bit long ints'
+  endif
+  new
+  call setline(1, 'text')
+  call assert_fails('|.44444444444444444444444', 'E1247:')
+  call assert_fails('|.9223372036854775806', 'E1247:')
+  bwipe!
+endfunc
+
+
 " vim: shiftwidth=2 sts=2 expandtab
--- a/src/testdir/test_normal.vim
+++ b/src/testdir/test_normal.vim
@@ -3519,4 +3519,25 @@ func Test_normal_gj_on_extra_wide_char()
   bw!
 endfunc
 
+func Test_normal_count_out_of_range()
+  new
+  call setline(1, 'text')
+  normal 44444444444|
+  call assert_equal(999999999, v:count)
+  normal 444444444444|
+  call assert_equal(999999999, v:count)
+  normal 4444444444444|
+  call assert_equal(999999999, v:count)
+  normal 4444444444444444444|
+  call assert_equal(999999999, v:count)
+
+  normal 9y99999999|
+  call assert_equal(899999991, v:count)
+  normal 10y99999999|
+  call assert_equal(999999999, v:count)
+  normal 44444444444y44444444444|
+  call assert_equal(999999999, v:count)
+  bwipe!
+endfunc
+
 " vim: shiftwidth=2 sts=2 expandtab
--- a/src/version.c
+++ b/src/version.c
@@ -758,6 +758,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    3659,
+/**/
     3658,
 /**/
     3657,