mirror of
https://github.com/neovim/neovim.git
synced 2025-09-18 09:18:19 +00:00
vim-patch:8.2.3659: integer overflow with large line number
Problem: Integer overflow with large line number.
Solution: Check for overflow. (closes vim/vim#9202)
03725c5795
Put E1247 in globals.h as E1240 is also there.
Do not make getdigits() abort.
This commit is contained in:
@@ -4141,7 +4141,11 @@ static linenr_T get_address(exarg_T *eap, char_u **ptr, cmd_addr_T addr_type, in
|
||||
if (!ascii_isdigit(*cmd)) { // '+' is '+1', but '+0' is not '+1'
|
||||
n = 1;
|
||||
} else {
|
||||
n = getdigits(&cmd, true, 0);
|
||||
n = getdigits(&cmd, false, MAXLNUM);
|
||||
if (n == MAXLNUM) {
|
||||
emsg(_(e_line_number_out_of_range));
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
if (addr_type == ADDR_TABS_RELATIVE) {
|
||||
@@ -4160,6 +4164,10 @@ static linenr_T get_address(exarg_T *eap, char_u **ptr, cmd_addr_T addr_type, in
|
||||
if (i == '-') {
|
||||
lnum -= n;
|
||||
} else {
|
||||
if (n >= LONG_MAX - lnum) {
|
||||
emsg(_(e_line_number_out_of_range));
|
||||
goto error;
|
||||
}
|
||||
lnum += n;
|
||||
}
|
||||
}
|
||||
|
@@ -1002,6 +1002,8 @@ EXTERN char e_cannot_define_autocommands_for_all_events[] INIT(= N_("E1155: Cann
|
||||
|
||||
EXTERN char e_resulting_text_too_long[] INIT(= N_("E1240: Resulting text too long"));
|
||||
|
||||
EXTERN char e_line_number_out_of_range[] INIT(= N_("E1247: Line number out of range"));
|
||||
|
||||
EXTERN char e_highlight_group_name_too_long[] INIT(= N_("E1249: Highlight group name too long"));
|
||||
|
||||
EXTERN char top_bot_msg[] INIT(= N_("search hit TOP, continuing at BOTTOM"));
|
||||
|
@@ -824,15 +824,12 @@ static bool normal_get_command_count(NormalState *s)
|
||||
if (s->c == K_DEL || s->c == K_KDEL) {
|
||||
s->ca.count0 /= 10;
|
||||
del_from_showcmd(4); // delete the digit and ~@%
|
||||
} else if (s->ca.count0 >= 999999999L) {
|
||||
s->ca.count0 = 999999999L;
|
||||
} else {
|
||||
s->ca.count0 = s->ca.count0 * 10 + (s->c - '0');
|
||||
}
|
||||
|
||||
if (s->ca.count0 < 0) {
|
||||
// overflow
|
||||
s->ca.count0 = 999999999L;
|
||||
}
|
||||
|
||||
// Set v:count here, when called from main() and not a stuffed
|
||||
// command, so that v:count can be used in an expression mapping
|
||||
// right after the count. Do set it for redo.
|
||||
@@ -1046,14 +1043,14 @@ static int normal_execute(VimState *state, int key)
|
||||
// If you give a count before AND after the operator, they are
|
||||
// multiplied.
|
||||
if (s->ca.count0) {
|
||||
s->ca.count0 = (long)((uint64_t)s->ca.count0 * (uint64_t)s->ca.opcount);
|
||||
if (s->ca.opcount >= 999999999L / s->ca.count0) {
|
||||
s->ca.count0 = 999999999L;
|
||||
} else {
|
||||
s->ca.count0 *= s->ca.opcount;
|
||||
}
|
||||
} else {
|
||||
s->ca.count0 = s->ca.opcount;
|
||||
}
|
||||
if (s->ca.count0 < 0) {
|
||||
// overflow
|
||||
s->ca.count0 = 999999999L;
|
||||
}
|
||||
}
|
||||
|
||||
// Always remember the count. It will be set to zero (on the next call,
|
||||
|
@@ -409,4 +409,18 @@ func Test_not_break_expression_register()
|
||||
call assert_equal('1+1', getreg('=', 1))
|
||||
endfunc
|
||||
|
||||
func Test_address_line_overflow()
|
||||
throw 'Skipped: v:sizeoflong is N/A' " use legacy/excmd_spec.lua instead
|
||||
|
||||
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
|
||||
|
@@ -2779,4 +2779,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
|
||||
|
32
test/functional/legacy/excmd_spec.lua
Normal file
32
test/functional/legacy/excmd_spec.lua
Normal file
@@ -0,0 +1,32 @@
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
local clear = helpers.clear
|
||||
local exec_lua = helpers.exec_lua
|
||||
local meths = helpers.meths
|
||||
local source = helpers.source
|
||||
local eq = helpers.eq
|
||||
|
||||
local function sizeoflong()
|
||||
if not exec_lua('return pcall(require, "ffi")') then
|
||||
pending('missing LuaJIT FFI')
|
||||
end
|
||||
return exec_lua('return require("ffi").sizeof(require("ffi").typeof("long"))')
|
||||
end
|
||||
|
||||
describe('Ex command', function()
|
||||
before_each(clear)
|
||||
after_each(function() eq({}, meths.get_vvar('errors')) end)
|
||||
|
||||
it('checks for address line overflow', function()
|
||||
if sizeoflong() < 8 then
|
||||
pending('Skipped: only works with 64 bit long ints')
|
||||
end
|
||||
|
||||
source [[
|
||||
new
|
||||
call setline(1, 'text')
|
||||
call assert_fails('|.44444444444444444444444', 'E1247:')
|
||||
call assert_fails('|.9223372036854775806', 'E1247:')
|
||||
bwipe!
|
||||
]]
|
||||
end)
|
||||
end)
|
Reference in New Issue
Block a user