summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2021-11-24 12:17:53 +0000
committerBram Moolenaar <Bram@vim.org>2021-11-24 12:17:53 +0000
commit03725c5795ae5b8c14da4a39cd0ce723c6dd4304 (patch)
tree9e95a417b4ae557702cec2d36858cd45d4ef9000
parent48608b4a4bfab4b9c0c9199d57b7e876c56db74c (diff)
patch 8.2.3659: integer overflow with large line numberv8.2.3659
Problem: Integer overflow with large line number. Solution: Check for overflow. (closes #9202)
-rw-r--r--src/errors.h2
-rw-r--r--src/ex_docmd.c16
-rw-r--r--src/normal.c17
-rw-r--r--src/testdir/test_excmd.vim12
-rw-r--r--src/testdir/test_normal.vim21
-rw-r--r--src/version.c2
6 files changed, 64 insertions, 6 deletions
diff --git a/src/errors.h b/src/errors.h
index cde98461ec..6346bf249a 100644
--- a/src/errors.h
+++ b/src/errors.h
@@ -688,3 +688,5 @@ EXTERN char e_cannot_expand_sfile_in_vim9_function[]
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"));
diff --git a/src/ex_docmd.c b/src/ex_docmd.c
index 76511de703..d74ef90263 100644
--- 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 == '?');
diff --git a/src/normal.c b/src/normal.c
index 56fae51dac..adce932057 100644
--- 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;
}
/*
diff --git a/src/testdir/test_excmd.vim b/src/testdir/test_excmd.vim
index 773a1a33e1..67b95bb3bd 100644
--- 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
diff --git a/src/testdir/test_normal.vim b/src/testdir/test_normal.vim
index e17aca4128..732456df66 100644
--- 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
diff --git a/src/version.c b/src/version.c
index a261ebd453..c56391f356 100644
--- 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,