mirror of
https://github.com/neovim/neovim
synced 2025-07-18 10:11:50 +00:00
fix(eval): checking for a non-empty string is too strict (#15987)
Cherry-pick check_for_nonempty_string() from patch vim-8.2.2133 and
apply it on the bases of https://github.com/neovim/neovim/pull/13489
2a9d5d386b
This commit is contained in:
@ -2201,7 +2201,7 @@ static void f_win_execute(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
|||||||
/// "exepath()" function
|
/// "exepath()" function
|
||||||
static void f_exepath(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
static void f_exepath(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
||||||
{
|
{
|
||||||
if (tv_check_for_string(&argvars[0]) == FAIL) {
|
if (tv_check_for_nonempty_string(&argvars[0]) == FAIL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2661,9 +2661,9 @@ static void f_fnamemodify(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
|||||||
char buf[NUMBUFLEN];
|
char buf[NUMBUFLEN];
|
||||||
const char *fname = tv_get_string_chk(&argvars[0]);
|
const char *fname = tv_get_string_chk(&argvars[0]);
|
||||||
const char *const mods = tv_get_string_buf_chk(&argvars[1], buf);
|
const char *const mods = tv_get_string_buf_chk(&argvars[1], buf);
|
||||||
if (fname == NULL || mods == NULL) {
|
if (fname == NULL) {
|
||||||
fname = NULL;
|
fname = NULL;
|
||||||
} else {
|
} else if (mods != NULL && *mods != NUL) {
|
||||||
len = strlen(fname);
|
len = strlen(fname);
|
||||||
size_t usedlen = 0;
|
size_t usedlen = 0;
|
||||||
if (*mods != NUL) {
|
if (*mods != NUL) {
|
||||||
|
@ -3146,19 +3146,31 @@ float_T tv_get_float(const typval_T *const tv)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Give an error and return FAIL unless "tv" is a non-empty string.
|
// Give an error and return FAIL unless "tv" is a string.
|
||||||
int tv_check_for_string(const typval_T *const tv)
|
int tv_check_for_string(const typval_T *const tv)
|
||||||
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE
|
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE
|
||||||
{
|
{
|
||||||
if (tv->v_type != VAR_STRING
|
if (tv->v_type != VAR_STRING) {
|
||||||
|| tv->vval.v_string == NULL
|
|
||||||
|| *tv->vval.v_string == NUL) {
|
|
||||||
EMSG(_(e_stringreq));
|
EMSG(_(e_stringreq));
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Give an error and return FAIL unless "tv" is a non-empty string.
|
||||||
|
int tv_check_for_nonempty_string(const typval_T *const tv)
|
||||||
|
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE
|
||||||
|
{
|
||||||
|
if (tv_check_for_string(tv) == FAIL) {
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
if (tv->vval.v_string == NULL || *tv->vval.v_string == NUL) {
|
||||||
|
EMSG(_(e_non_empty_string_required));
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the string value of a "stringish" VimL object.
|
/// Get the string value of a "stringish" VimL object.
|
||||||
///
|
///
|
||||||
/// @param[in] tv Object to get value of.
|
/// @param[in] tv Object to get value of.
|
||||||
|
@ -994,6 +994,8 @@ EXTERN char_u e_floatonly[] INIT(=N_(
|
|||||||
"E5601: Cannot close window, only floating window would remain"));
|
"E5601: Cannot close window, only floating window would remain"));
|
||||||
EXTERN char_u e_floatexchange[] INIT(=N_("E5602: Cannot exchange or rotate float"));
|
EXTERN char_u e_floatexchange[] INIT(=N_("E5602: Cannot exchange or rotate float"));
|
||||||
|
|
||||||
|
EXTERN char e_non_empty_string_required[] INIT(= N_("E1142: Non-empty string required"));
|
||||||
|
|
||||||
EXTERN char e_cannot_define_autocommands_for_all_events[] INIT(=
|
EXTERN char e_cannot_define_autocommands_for_all_events[] INIT(=
|
||||||
N_(
|
N_(
|
||||||
"E1155: Cannot define autocommands for ALL events"));
|
"E1155: Cannot define autocommands for ALL events"));
|
||||||
|
@ -18,7 +18,7 @@ describe('executable()', function()
|
|||||||
end)
|
end)
|
||||||
|
|
||||||
it('fails for invalid values', function()
|
it('fails for invalid values', function()
|
||||||
for _, input in ipairs({'""', 'v:null', 'v:true', 'v:false', '{}', '[]'}) do
|
for _, input in ipairs({'v:null', 'v:true', 'v:false', '{}', '[]'}) do
|
||||||
eq('Vim(call):E928: String required', exc_exec('call executable('..input..')'))
|
eq('Vim(call):E928: String required', exc_exec('call executable('..input..')'))
|
||||||
end
|
end
|
||||||
command('let $PATH = fnamemodify("./test/functional/fixtures/bin", ":p")')
|
command('let $PATH = fnamemodify("./test/functional/fixtures/bin", ":p")')
|
||||||
@ -27,6 +27,10 @@ describe('executable()', function()
|
|||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
it('returns 0 for empty strings', function()
|
||||||
|
eq(0, call('executable', '""'))
|
||||||
|
end)
|
||||||
|
|
||||||
it('returns 0 for non-existent files', function()
|
it('returns 0 for non-existent files', function()
|
||||||
eq(0, call('executable', 'no_such_file_exists_209ufq23f'))
|
eq(0, call('executable', 'no_such_file_exists_209ufq23f'))
|
||||||
end)
|
end)
|
||||||
|
@ -20,9 +20,10 @@ describe('exepath()', function()
|
|||||||
end)
|
end)
|
||||||
|
|
||||||
it('fails for invalid values', function()
|
it('fails for invalid values', function()
|
||||||
for _, input in ipairs({'""', 'v:null', 'v:true', 'v:false', '{}', '[]'}) do
|
for _, input in ipairs({'v:null', 'v:true', 'v:false', '{}', '[]'}) do
|
||||||
eq('Vim(call):E928: String required', exc_exec('call exepath('..input..')'))
|
eq('Vim(call):E928: String required', exc_exec('call exepath('..input..')'))
|
||||||
end
|
end
|
||||||
|
eq('Vim(call):E1142: Non-empty string required', exc_exec('call exepath("")'))
|
||||||
command('let $PATH = fnamemodify("./test/functional/fixtures/bin", ":p")')
|
command('let $PATH = fnamemodify("./test/functional/fixtures/bin", ":p")')
|
||||||
for _, input in ipairs({'v:null', 'v:true', 'v:false'}) do
|
for _, input in ipairs({'v:null', 'v:true', 'v:false'}) do
|
||||||
eq('Vim(call):E928: String required', exc_exec('call exepath('..input..')'))
|
eq('Vim(call):E928: String required', exc_exec('call exepath('..input..')'))
|
||||||
|
@ -161,7 +161,7 @@ describe('NULL', function()
|
|||||||
null_test('does not crash :echomsg', 'echomsg S', 0)
|
null_test('does not crash :echomsg', 'echomsg S', 0)
|
||||||
null_test('does not crash :execute', 'execute S', 0)
|
null_test('does not crash :execute', 'execute S', 0)
|
||||||
null_expr_test('does not crash execute()', 'execute(S)', 0, '')
|
null_expr_test('does not crash execute()', 'execute(S)', 0, '')
|
||||||
null_expr_test('makes executable() error out', 'executable(S)', 'E928: String required', 0)
|
null_expr_test('does not crash executable()', 'executable(S)', 0, 0)
|
||||||
null_expr_test('makes timer_start() error out', 'timer_start(0, S)', 'E921: Invalid callback argument', -1)
|
null_expr_test('makes timer_start() error out', 'timer_start(0, S)', 'E921: Invalid callback argument', -1)
|
||||||
null_expr_test('does not crash filereadable()', 'filereadable(S)', 0, 0)
|
null_expr_test('does not crash filereadable()', 'filereadable(S)', 0, 0)
|
||||||
null_expr_test('does not crash filewritable()', 'filewritable(S)', 0, 0)
|
null_expr_test('does not crash filewritable()', 'filewritable(S)', 0, 0)
|
||||||
|
Reference in New Issue
Block a user