mirror of
https://github.com/neovim/neovim.git
synced 2025-09-18 17:28:23 +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'
|
if (!ascii_isdigit(*cmd)) { // '+' is '+1', but '+0' is not '+1'
|
||||||
n = 1;
|
n = 1;
|
||||||
} else {
|
} 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) {
|
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 == '-') {
|
if (i == '-') {
|
||||||
lnum -= n;
|
lnum -= n;
|
||||||
} else {
|
} else {
|
||||||
|
if (n >= LONG_MAX - lnum) {
|
||||||
|
emsg(_(e_line_number_out_of_range));
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
lnum += n;
|
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_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 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"));
|
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) {
|
if (s->c == K_DEL || s->c == K_KDEL) {
|
||||||
s->ca.count0 /= 10;
|
s->ca.count0 /= 10;
|
||||||
del_from_showcmd(4); // delete the digit and ~@%
|
del_from_showcmd(4); // delete the digit and ~@%
|
||||||
|
} else if (s->ca.count0 >= 999999999L) {
|
||||||
|
s->ca.count0 = 999999999L;
|
||||||
} else {
|
} else {
|
||||||
s->ca.count0 = s->ca.count0 * 10 + (s->c - '0');
|
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
|
// Set v:count here, when called from main() and not a stuffed
|
||||||
// command, so that v:count can be used in an expression mapping
|
// command, so that v:count can be used in an expression mapping
|
||||||
// right after the count. Do set it for redo.
|
// 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
|
// If you give a count before AND after the operator, they are
|
||||||
// multiplied.
|
// multiplied.
|
||||||
if (s->ca.count0) {
|
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 {
|
} else {
|
||||||
s->ca.count0 = s->ca.opcount;
|
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,
|
// 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))
|
call assert_equal('1+1', getreg('=', 1))
|
||||||
endfunc
|
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
|
" vim: shiftwidth=2 sts=2 expandtab
|
||||||
|
@@ -2779,4 +2779,25 @@ func Test_normal_gj_on_extra_wide_char()
|
|||||||
bw!
|
bw!
|
||||||
endfunc
|
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
|
" 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