0
0
mirror of https://github.com/vim/vim.git synced 2025-09-25 03:54:15 -04:00

patch 9.0.0440: crash when using mkdir() with "R" flag in compiled function

Problem:    Crash when using mkdir() with "R" flag in compiled function.
Solution:   Reserve a variable for deferred function calls.  Handle more than
            one argument.
This commit is contained in:
Bram Moolenaar
2022-09-11 11:49:22 +01:00
parent 88b79cb7d4
commit f5fec05c7f
4 changed files with 35 additions and 48 deletions

View File

@@ -29,7 +29,7 @@ def TestCompilingError()
enddef enddef
defcompile defcompile
END END
writefile(lines, 'XTest_compile_error') writefile(lines, 'XTest_compile_error', 'D')
var buf = g:RunVimInTerminal('-S XTest_compile_error', var buf = g:RunVimInTerminal('-S XTest_compile_error',
{rows: 10, wait_for_ruler: 0}) {rows: 10, wait_for_ruler: 0})
g:WaitForAssert(() => assert_match('Error detected while compiling command line.*Fails.*Variable not found: nothing', g:WaitForAssert(() => assert_match('Error detected while compiling command line.*Fails.*Variable not found: nothing',
@@ -37,12 +37,11 @@ def TestCompilingError()
# clean up # clean up
g:StopVimInTerminal(buf) g:StopVimInTerminal(buf)
delete('XTest_compile_error')
enddef enddef
def TestCompilingErrorInTry() def TestCompilingErrorInTry()
var dir = 'Xcompdir/autoload' var dir = 'Xcompdir/autoload'
mkdir(dir, 'p') mkdir(dir, 'pR')
var lines =<< trim END var lines =<< trim END
vim9script vim9script
@@ -62,7 +61,7 @@ def TestCompilingErrorInTry()
endtry endtry
END END
lines[1] = 'set rtp=' .. getcwd() .. '/Xcompdir' lines[1] = 'set rtp=' .. getcwd() .. '/Xcompdir'
writefile(lines, 'XTest_compile_error') writefile(lines, 'XTest_compile_error', 'D')
var buf = g:RunVimInTerminal('-S XTest_compile_error', {rows: 10, wait_for_ruler: 0}) var buf = g:RunVimInTerminal('-S XTest_compile_error', {rows: 10, wait_for_ruler: 0})
g:WaitForAssert(() => assert_match('Error detected while compiling command line.*function script#OnlyCompiled.*Invalid command: invalid', g:WaitForAssert(() => assert_match('Error detected while compiling command line.*function script#OnlyCompiled.*Invalid command: invalid',
@@ -70,8 +69,6 @@ def TestCompilingErrorInTry()
# clean up # clean up
g:StopVimInTerminal(buf) g:StopVimInTerminal(buf)
delete('XTest_compile_error')
delete('Xcompdir', 'rf')
enddef enddef
def Test_comment_error() def Test_comment_error()
@@ -171,7 +168,7 @@ enddef
def Test_autoload_name_mismatch() def Test_autoload_name_mismatch()
var dir = 'Xnamedir/autoload' var dir = 'Xnamedir/autoload'
mkdir(dir, 'p') mkdir(dir, 'pR')
var lines =<< trim END var lines =<< trim END
vim9script vim9script
@@ -190,12 +187,11 @@ def Test_autoload_name_mismatch()
v9.CheckScriptFailure(lines, 'E117:', 1) v9.CheckScriptFailure(lines, 'E117:', 1)
&rtp = save_rtp &rtp = save_rtp
delete('Xnamedir', 'rf')
enddef enddef
def Test_autoload_names() def Test_autoload_names()
var dir = 'Xandir/autoload' var dir = 'Xandir/autoload'
mkdir(dir, 'p') mkdir(dir, 'pR')
var lines =<< trim END var lines =<< trim END
func foobar#function() func foobar#function()
@@ -218,12 +214,11 @@ def Test_autoload_names()
v9.CheckDefAndScriptSuccess(lines) v9.CheckDefAndScriptSuccess(lines)
&rtp = save_rtp &rtp = save_rtp
delete('Xandir', 'rf')
enddef enddef
def Test_autoload_error_in_script() def Test_autoload_error_in_script()
var dir = 'Xaedir/autoload' var dir = 'Xaedir/autoload'
mkdir(dir, 'p') mkdir(dir, 'pR')
var lines =<< trim END var lines =<< trim END
func scripterror#function() func scripterror#function()
@@ -264,7 +259,6 @@ def Test_autoload_error_in_script()
assert_equal('yes', g:called_function) assert_equal('yes', g:called_function)
&rtp = save_rtp &rtp = save_rtp
delete('Xaedir', 'rf')
enddef enddef
def s:CallRecursive(n: number): number def s:CallRecursive(n: number): number
@@ -1298,7 +1292,7 @@ def Test_call_wrong_args()
enddef enddef
defcompile defcompile
END END
writefile(lines, 'Xscript') writefile(lines, 'Xscript', 'D')
didCatch = false didCatch = false
try try
source Xscript source Xscript
@@ -1308,8 +1302,6 @@ def Test_call_wrong_args()
didCatch = true didCatch = true
endtry endtry
assert_true(didCatch) assert_true(didCatch)
delete('Xscript')
enddef enddef
def Test_call_funcref_wrong_args() def Test_call_funcref_wrong_args()
@@ -2306,9 +2298,8 @@ def Test_vim9script_call()
'morelines', 'morelines',
name) name)
END END
writefile(lines, 'Xcall.vim') writefile(lines, 'Xcall.vim', 'D')
source Xcall.vim source Xcall.vim
delete('Xcall.vim')
enddef enddef
def Test_vim9script_call_fail_decl() def Test_vim9script_call_fail_decl()
@@ -2343,9 +2334,8 @@ def Test_vim9script_call_fail_const()
enddef enddef
defcompile defcompile
END END
writefile(lines, 'Xcall_const.vim') writefile(lines, 'Xcall_const.vim', 'D')
assert_fails('source Xcall_const.vim', 'E46:', '', 1, 'MyFunc') assert_fails('source Xcall_const.vim', 'E46:', '', 1, 'MyFunc')
delete('Xcall_const.vim')
lines =<< trim END lines =<< trim END
const g:Aconst = 77 const g:Aconst = 77
@@ -2385,11 +2375,9 @@ def Test_delfunc()
delfunc g:GoneSoon delfunc g:GoneSoon
CallGoneSoon() CallGoneSoon()
END END
writefile(lines, 'XToDelFunc') writefile(lines, 'XToDelFunc', 'D')
assert_fails('so XToDelFunc', 'E933:', '', 1, 'CallGoneSoon') assert_fails('so XToDelFunc', 'E933:', '', 1, 'CallGoneSoon')
assert_fails('so XToDelFunc', 'E933:', '', 1, 'CallGoneSoon') assert_fails('so XToDelFunc', 'E933:', '', 1, 'CallGoneSoon')
delete('XToDelFunc')
enddef enddef
func Test_free_dict_while_in_funcstack() func Test_free_dict_while_in_funcstack()
@@ -2454,10 +2442,8 @@ def Test_vim9script_func()
endfunc endfunc
Func('text') Func('text')
END END
writefile(lines, 'XVim9Func') writefile(lines, 'XVim9Func', 'D')
so XVim9Func so XVim9Func
delete('XVim9Func')
enddef enddef
let s:funcResult = 0 let s:funcResult = 0
@@ -2700,7 +2686,7 @@ def Test_error_reporting()
enddef enddef
defcompile defcompile
END END
writefile(lines, 'Xdef') writefile(lines, 'Xdef', 'D')
try try
source Xdef source Xdef
assert_report('should have failed') assert_report('should have failed')
@@ -2749,8 +2735,6 @@ def Test_error_reporting()
v:throwpoint->assert_match('_Func, line 3$') v:throwpoint->assert_match('_Func, line 3$')
endtry endtry
delfunc! g:Func delfunc! g:Func
delete('Xdef')
enddef enddef
def Test_deleted_function() def Test_deleted_function()
@@ -3421,14 +3405,12 @@ def s:TreeWalk(dir: string): list<any>
enddef enddef
def Test_closure_in_map() def Test_closure_in_map()
mkdir('XclosureDir/tdir', 'p') mkdir('XclosureDir/tdir', 'pR')
writefile(['111'], 'XclosureDir/file1') writefile(['111'], 'XclosureDir/file1')
writefile(['222'], 'XclosureDir/file2') writefile(['222'], 'XclosureDir/file2')
writefile(['333'], 'XclosureDir/tdir/file3') writefile(['333'], 'XclosureDir/tdir/file3')
TreeWalk('XclosureDir')->assert_equal(['file1', 'file2', {tdir: ['file3']}]) TreeWalk('XclosureDir')->assert_equal(['file1', 'file2', {tdir: ['file3']}])
delete('XclosureDir', 'rf')
enddef enddef
def Test_invalid_function_name() def Test_invalid_function_name()
@@ -3532,12 +3514,11 @@ func Test_partial_call_fails()
var it = Iter(l) var it = Iter(l)
echo it.__next__() echo it.__next__()
END END
call writefile(lines, 'XpartialCall') call writefile(lines, 'XpartialCall', 'D')
try try
source XpartialCall source XpartialCall
catch /E1248:/ catch /E1248:/
endtry endtry
call delete('XpartialCall')
endfunc endfunc
def Test_cmd_modifier() def Test_cmd_modifier()
@@ -3631,9 +3612,9 @@ def Test_did_emsg_reset()
nno <F3> <cmd>call <sid>Func()<cr> nno <F3> <cmd>call <sid>Func()<cr>
feedkeys("\<F3>\e", 'xt') feedkeys("\<F3>\e", 'xt')
END END
writefile(lines, 'XemsgReset') writefile(lines, 'XemsgReset', 'D')
assert_fails('so XemsgReset', ['E684:', 'E684:'], lines, 2) assert_fails('so XemsgReset', ['E684:', 'E684:'], lines, 2)
delete('XemsgReset')
nunmap <F3> nunmap <F3>
au! BufWinLeave au! BufWinLeave
enddef enddef
@@ -3698,7 +3679,7 @@ def Test_cmdmod_silent_restored()
END END
# can't use CheckScriptFailure, it ignores the :silent! # can't use CheckScriptFailure, it ignores the :silent!
var fname = 'Xdefsilent' var fname = 'Xdefsilent'
writefile(lines, fname) writefile(lines, fname, 'D')
var caught = 'no' var caught = 'no'
try try
exe 'source ' .. fname exe 'source ' .. fname
@@ -3707,7 +3688,6 @@ def Test_cmdmod_silent_restored()
assert_match('Func, line 4', v:throwpoint) assert_match('Func, line 4', v:throwpoint)
endtry endtry
assert_equal('yes', caught) assert_equal('yes', caught)
delete(fname)
enddef enddef
def Test_cmdmod_silent_nested() def Test_cmdmod_silent_nested()
@@ -3809,7 +3789,7 @@ def Run_Test_opfunc_error()
feedkeys('g@l', 'n') feedkeys('g@l', 'n')
feedkeys('llll') feedkeys('llll')
END END
call writefile(lines, 'XTest_opfunc_error') call writefile(lines, 'XTest_opfunc_error', 'D')
var buf = g:RunVimInTerminal('-S XTest_opfunc_error', {rows: 6, wait_for_ruler: 0}) var buf = g:RunVimInTerminal('-S XTest_opfunc_error', {rows: 6, wait_for_ruler: 0})
g:WaitForAssert(() => assert_match('Press ENTER', term_getline(buf, 6))) g:WaitForAssert(() => assert_match('Press ENTER', term_getline(buf, 6)))
@@ -3817,7 +3797,6 @@ def Run_Test_opfunc_error()
# clean up # clean up
g:StopVimInTerminal(buf) g:StopVimInTerminal(buf)
delete('XTest_opfunc_error')
enddef enddef
" this was crashing on exit " this was crashing on exit
@@ -3890,14 +3869,13 @@ def Test_script_local_other_script()
function s:close_cb(...) function s:close_cb(...)
endfunction endfunction
END END
lines->writefile('Xlegacy.vim') lines->writefile('Xlegacy.vim', 'D')
source Xlegacy.vim source Xlegacy.vim
g:LegacyJob() g:LegacyJob()
g:LegacyJob() g:LegacyJob()
g:LegacyJob() g:LegacyJob()
delfunc g:LegacyJob delfunc g:LegacyJob
delete('Xlegacy.vim')
enddef enddef
def Test_check_func_arg_types() def Test_check_func_arg_types()

View File

@@ -703,6 +703,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
440,
/**/ /**/
439, 439,
/**/ /**/

View File

@@ -932,11 +932,17 @@ defer_command(int var_idx, int argcount, ectx_T *ectx)
return FAIL; return FAIL;
func_tv = STACK_TV_BOT(-argcount - 1); func_tv = STACK_TV_BOT(-argcount - 1);
// TODO: check type is a funcref if (func_tv->v_type != VAR_FUNC && func_tv->v_type != VAR_PARTIAL)
{
semsg(_(e_expected_str_but_got_str),
"function or partial",
vartype_name(func_tv->v_type));
return FAIL;
}
list_set_item(l, 0, func_tv); list_set_item(l, 0, func_tv);
for (i = 1; i <= argcount; ++i) for (i = 0; i < argcount; ++i)
list_set_item(l, i, STACK_TV_BOT(-argcount + i - 1)); list_set_item(l, i + 1, STACK_TV_BOT(-argcount + i));
ectx->ec_stack.ga_len -= argcount + 1; ectx->ec_stack.ga_len -= argcount + 1;
return OK; return OK;
} }
@@ -962,7 +968,7 @@ add_defer_function(char_u *name, int argcount, typval_T *argvars)
return FAIL; return FAIL;
} }
l = add_defer_item(dfunc->df_defer_var_idx - 1, 1, current_ectx); l = add_defer_item(dfunc->df_defer_var_idx - 1, argcount, current_ectx);
if (l == NULL) if (l == NULL)
{ {
vim_free(name); vim_free(name);

View File

@@ -833,10 +833,11 @@ compile_call(
} }
} }
if (STRCMP(name, "writefile") == 0 && argcount > 2) if ((STRCMP(name, "writefile") == 0 && argcount > 2)
|| (STRCMP(name, "mkdir") == 0 && argcount > 1))
{ {
// May have the "D" flag, reserve a variable for a deferred // May have the "D" or "R" flag, reserve a variable for a
// function call. // deferred function call.
if (get_defer_var_idx(cctx) == 0) if (get_defer_var_idx(cctx) == 0)
idx = -1; idx = -1;
} }