Merge pull request #17433 from seandewar/vim-8.2.3492

vim-patch:8.2.{3492,3493,3570,3573,3574,3575,3577,3601}: put overflow checking shenanigans
This commit is contained in:
Sean Dewar 2022-02-18 00:09:11 +00:00 committed by GitHub
commit 592f4a7c08
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 127 additions and 13 deletions

View File

@ -494,6 +494,9 @@ Eval:
*js_encode()*
*js_decode()*
*v:none* (used by Vim to represent JavaScript "undefined"); use |v:null| instead.
*v:sizeofint*
*v:sizeoflong*
*v:sizeofpointer*
Events:
*SigUSR1* Use |Signal| to detect `SIGUSR1` signal instead.

View File

@ -3314,18 +3314,28 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
}
}
// insert the new text
// Insert the new text.
// First check for multiplication overflow.
if (yanklen + spaces != 0
&& count > ((INT_MAX - (bd.startspaces + bd.endspaces)) / (yanklen + spaces))) {
emsg(_(e_resulting_text_too_long));
break;
}
totlen = (size_t)(count * (yanklen + spaces)
+ bd.startspaces + bd.endspaces);
int addcount = (int)totlen + lines_appended;
newp = (char_u *)xmalloc(totlen + oldlen + 1);
// copy part up to cursor to new line
ptr = newp;
memmove(ptr, oldp, (size_t)bd.textcol);
ptr += bd.textcol;
// may insert some spaces before the new text
memset(ptr, ' ', (size_t)bd.startspaces);
ptr += bd.startspaces;
// insert the new text
for (long j = 0; j < count; j++) {
memmove(ptr, y_array[i], (size_t)yanklen);
@ -3339,9 +3349,11 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
addcount -= spaces;
}
}
// may insert some spaces after the new text
memset(ptr, ' ', (size_t)bd.endspaces);
ptr += bd.endspaces;
// move the text after the cursor to the end of the line.
int columns = (int)oldlen - bd.textcol - delcount + 1;
assert(columns >= 0);
@ -3430,10 +3442,18 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
}
}
do {
if (count == 0 || yanklen == 0) {
if (VIsual_active) {
lnum = end_lnum;
}
} else if (count > INT_MAX / yanklen) {
// multiplication overflow
emsg(_(e_resulting_text_too_long));
} else {
totlen = (size_t)(count * yanklen);
if (totlen > 0) {
do {
oldp = ml_get(lnum);
oldlen = STRLEN(oldp);
if (lnum > start_lnum) {
pos_T pos = {
.lnum = lnum,
@ -3444,11 +3464,11 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
col = MAXCOL;
}
}
if (VIsual_active && col > (int)STRLEN(oldp)) {
if (VIsual_active && col > (colnr_T)oldlen) {
lnum++;
continue;
}
newp = (char_u *)xmalloc((size_t)(STRLEN(oldp) + totlen + 1));
newp = (char_u *)xmalloc(totlen + oldlen + 1);
memmove(newp, oldp, (size_t)col);
ptr = newp + col;
for (i = 0; i < (size_t)count; i++) {
@ -3470,14 +3490,14 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
changed_bytes(lnum, col);
extmark_splice_cols(curbuf, (int)lnum-1, col,
0, (int)totlen, kExtmarkUndo);
}
if (VIsual_active) {
lnum++;
}
} while (VIsual_active && lnum <= end_lnum);
if (VIsual_active) {
lnum++;
}
} while (VIsual_active && lnum <= end_lnum);
if (VIsual_active) { // reset lnum to the last visual line
lnum--;
if (VIsual_active) { // reset lnum to the last visual line
lnum--;
}
}
// put '] at the first byte of the last character
@ -5691,7 +5711,9 @@ static void str_to_reg(yankreg_T *y_ptr, MotionType yank_type, const char_u *str
// When appending, copy the previous line and free it after.
size_t extra = append ? STRLEN(pp[--lnum]) : 0;
char_u *s = xmallocz(line_len + extra);
memcpy(s, pp[lnum], extra);
if (extra > 0) {
memcpy(s, pp[lnum], extra);
}
memcpy(s + extra, start, line_len);
size_t s_len = extra + line_len;

View File

@ -138,6 +138,50 @@ func Test_p_with_count_leaves_mark_at_end()
bwipe!
endfunc
func Test_very_large_count()
new
" total put-length (21474837 * 100) brings 32 bit int overflow
let @" = repeat('x', 100)
call assert_fails('norm 21474837p', 'E1240:')
bwipe!
endfunc
func Test_very_large_count_64bit()
throw 'Skipped: v:sizeoflong is N/A' " use legacy/put_spec.lua instead
if v:sizeoflong < 8
throw 'Skipped: only works with 64 bit long ints'
endif
new
let @" = 'x'
call assert_fails('norm 44444444444444p', 'E1240:')
bwipe!
endfunc
func Test_very_large_count_block()
new
" total put-length (21474837 * 100) brings 32 bit int overflow
call setline(1, repeat('x', 100))
exe "norm \<C-V>99ly"
call assert_fails('norm 21474837p', 'E1240:')
bwipe!
endfunc
func Test_very_large_count_block_64bit()
throw 'Skipped: v:sizeoflong is N/A' " use legacy/put_spec.lua instead
if v:sizeoflong < 8
throw 'Skipped: only works with 64 bit long ints'
endif
new
call setline(1, 'x')
exe "norm \<C-V>y"
call assert_fails('norm 44444444444444p', 'E1240:')
bwipe!
endfunc
func Test_put_above_first_line()
new
let @" = 'text'

View File

@ -0,0 +1,45 @@
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('put', function()
before_each(clear)
after_each(function() eq({}, meths.get_vvar('errors')) end)
it('very large count 64-bit', function()
if sizeoflong() < 8 then
pending('Skipped: only works with 64 bit long ints')
end
source [[
new
let @" = 'x'
call assert_fails('norm 44444444444444p', 'E1240:')
bwipe!
]]
end)
it('very large count (visual block) 64-bit', function()
if sizeoflong() < 8 then
pending('Skipped: only works with 64 bit long ints')
end
source [[
new
call setline(1, 'x')
exe "norm \<C-V>y"
call assert_fails('norm 44444444444444p', 'E1240:')
bwipe!
]]
end)
end)