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:
@@ -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()
|
||||||
|
@@ -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,
|
||||||
/**/
|
/**/
|
||||||
|
@@ -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);
|
||||||
|
@@ -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;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user