Skip to content

Commit fa0ad0b

Browse files
committed
patch 8.0.0537: illegal memory access with :z and large count
Problem: Illegal memory access with :z and large count. Solution: Check for number overflow, using long instead of int. (Dominique Pelle, closes #1612)
1 parent 69f40be commit fa0ad0b

5 files changed

Lines changed: 92 additions & 5 deletions

File tree

src/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2122,10 +2122,10 @@ test_arglist \
21222122
test_delete \
21232123
test_diffmode \
21242124
test_digraph \
2125-
test_functions \
21262125
test_display \
21272126
test_edit \
21282127
test_ex_undo \
2128+
test_ex_z \
21292129
test_execute_func \
21302130
test_expand \
21312131
test_expand_dllpath \
@@ -2142,6 +2142,7 @@ test_arglist \
21422142
test_fnameescape \
21432143
test_fnamemodify \
21442144
test_fold \
2145+
test_functions \
21452146
test_ga \
21462147
test_gf \
21472148
test_glob2regpat \

src/ex_cmds.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4564,7 +4564,7 @@ ex_change(exarg_T *eap)
45644564
ex_z(exarg_T *eap)
45654565
{
45664566
char_u *x;
4567-
int bigness;
4567+
long bigness;
45684568
char_u *kind;
45694569
int minus = 0;
45704570
linenr_T start, end, curs, i;
@@ -4601,7 +4601,12 @@ ex_z(exarg_T *eap)
46014601
}
46024602
else
46034603
{
4604-
bigness = atoi((char *)x);
4604+
bigness = atol((char *)x);
4605+
4606+
/* bigness could be < 0 if atol(x) overflows. */
4607+
if (bigness > 2 * curbuf->b_ml.ml_line_count || bigness < 0)
4608+
bigness = 2 * curbuf->b_ml.ml_line_count;
4609+
46054610
p_window = bigness;
46064611
if (*kind == '=')
46074612
bigness += 2;

src/testdir/test_alot.vim

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,11 @@ source test_changedtick.vim
88
source test_cursor_func.vim
99
source test_delete.vim
1010
source test_ex_undo.vim
11+
source test_ex_z.vim
1112
source test_execute_func.vim
1213
source test_expand.vim
13-
source test_expr.vim
1414
source test_expand_dllpath.vim
15+
source test_expr.vim
1516
source test_feedkeys.vim
1617
source test_file_perm.vim
1718
source test_fileformat.vim
@@ -30,9 +31,9 @@ source test_join.vim
3031
source test_jumps.vim
3132
source test_lambda.vim
3233
source test_lispwords.vim
34+
source test_mapping.vim
3335
source test_match.vim
3436
source test_menu.vim
35-
source test_mapping.vim
3637
source test_messages.vim
3738
source test_partial.vim
3839
source test_popup.vim

src/testdir/test_ex_z.vim

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
" Test :z
2+
3+
func Test_z()
4+
call setline(1, range(1, 100))
5+
6+
let a = execute('20z3')
7+
call assert_equal("\n20\n21\n22", a)
8+
call assert_equal(22, line('.'))
9+
" 'window' should be set to the {count} value.
10+
call assert_equal(3, &window)
11+
12+
" If there is only one window, then twice the amount of 'scroll' is used.
13+
set scroll=2
14+
let a = execute('20z')
15+
call assert_equal("\n20\n21\n22\n23", a)
16+
call assert_equal(23, line('.'))
17+
18+
let a = execute('20z+3')
19+
" FIXME: I would expect the same result as '20z3' but it
20+
" gives "\n21\n22\n23" instead. Bug in Vim or in ":help :z"?
21+
"call assert_equal("\n20\n21\n22", a)
22+
"call assert_equal(22, line('.'))
23+
24+
let a = execute('20z-3')
25+
call assert_equal("\n18\n19\n20", a)
26+
call assert_equal(20, line('.'))
27+
28+
let a = execute('20z=3')
29+
call assert_match("^\n18\n19\n-\\+\n20\n-\\+\n21\n22$", a)
30+
call assert_equal(20, line('.'))
31+
32+
let a = execute('20z^3')
33+
call assert_equal("\n14\n15\n16\n17", a)
34+
call assert_equal(17, line('.'))
35+
36+
let a = execute('20z.3')
37+
call assert_equal("\n19\n20\n21", a)
38+
call assert_equal(21, line('.'))
39+
40+
let a = execute('20z#3')
41+
call assert_equal("\n 20 20\n 21 21\n 22 22", a)
42+
call assert_equal(22, line('.'))
43+
44+
let a = execute('20z#-3')
45+
call assert_equal("\n 18 18\n 19 19\n 20 20", a)
46+
call assert_equal(20, line('.'))
47+
48+
let a = execute('20z#=3')
49+
call assert_match("^\n 18 18\n 19 19\n-\\+\n 20 20\n-\\+\n 21 21\n 22 22$", a)
50+
call assert_equal(20, line('.'))
51+
52+
" Test with {count} bigger than the number of lines in buffer.
53+
let a = execute('20z1000')
54+
call assert_match("^\n20\n21\n.*\n99\n100$", a)
55+
call assert_equal(100, line('.'))
56+
57+
let a = execute('20z-1000')
58+
call assert_match("^\n1\n2\n.*\n19\n20$", a)
59+
call assert_equal(20, line('.'))
60+
61+
let a = execute('20z=1000')
62+
call assert_match("^\n1\n.*\n-\\+\n20\n-\\\+\n.*\n100$", a)
63+
call assert_equal(20, line('.'))
64+
65+
call assert_fails('20z=a', 'E144:')
66+
67+
set window& scroll&
68+
bw!
69+
endfunc
70+
71+
func Test_z_bug()
72+
" This used to access invalid memory as a result of an integer overflow
73+
" and freeze vim.
74+
normal ox
75+
normal Heat
76+
z777777776666666
77+
')
78+
endfunc

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -764,6 +764,8 @@ static char *(features[]) =
764764

765765
static int included_patches[] =
766766
{ /* Add new patch number below this line */
767+
/**/
768+
537,
767769
/**/
768770
536,
769771
/**/

0 commit comments

Comments
 (0)