diff options
author | Fabian <f.vioel@googlemail.com> | 2021-10-29 04:13:40 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-10-28 22:13:40 -0400 |
commit | 1dbbaf89bf5d3bcd1edac3af9938c2e2dd18f816 (patch) | |
tree | 1b1f9fd16f4405af5fe82744f42165a085d3a121 | |
parent | bb79e05f811968b398b3bedf95c012c888b96e44 (diff) | |
download | rneovim-1dbbaf89bf5d3bcd1edac3af9938c2e2dd18f816.tar.gz rneovim-1dbbaf89bf5d3bcd1edac3af9938c2e2dd18f816.tar.bz2 rneovim-1dbbaf89bf5d3bcd1edac3af9938c2e2dd18f816.zip |
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
https://github.com/vim/vim/commit/2a9d5d386bea8455b37c1accebc45683ec51d6fb
-rw-r--r-- | src/nvim/eval/funcs.c | 6 | ||||
-rw-r--r-- | src/nvim/eval/typval.c | 20 | ||||
-rw-r--r-- | src/nvim/globals.h | 2 | ||||
-rw-r--r-- | test/functional/vimscript/executable_spec.lua | 6 | ||||
-rw-r--r-- | test/functional/vimscript/exepath_spec.lua | 3 | ||||
-rw-r--r-- | test/functional/vimscript/null_spec.lua | 2 |
6 files changed, 29 insertions, 10 deletions
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 1c78e25639..d0f6c178df 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -2201,7 +2201,7 @@ static void f_win_execute(typval_T *argvars, typval_T *rettv, FunPtr fptr) /// "exepath()" function 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; } @@ -2661,9 +2661,9 @@ static void f_fnamemodify(typval_T *argvars, typval_T *rettv, FunPtr fptr) char buf[NUMBUFLEN]; const char *fname = tv_get_string_chk(&argvars[0]); const char *const mods = tv_get_string_buf_chk(&argvars[1], buf); - if (fname == NULL || mods == NULL) { + if (fname == NULL) { fname = NULL; - } else { + } else if (mods != NULL && *mods != NUL) { len = strlen(fname); size_t usedlen = 0; if (*mods != NUL) { diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c index 6300ce6150..4e845cffdd 100644 --- a/src/nvim/eval/typval.c +++ b/src/nvim/eval/typval.c @@ -3146,19 +3146,31 @@ float_T tv_get_float(const typval_T *const tv) 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) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE { - if (tv->v_type != VAR_STRING - || tv->vval.v_string == NULL - || *tv->vval.v_string == NUL) { + if (tv->v_type != VAR_STRING) { EMSG(_(e_stringreq)); return FAIL; } 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. /// /// @param[in] tv Object to get value of. diff --git a/src/nvim/globals.h b/src/nvim/globals.h index d1f6e2dbd9..21e186ec8c 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -994,6 +994,8 @@ EXTERN char_u e_floatonly[] INIT(=N_( "E5601: Cannot close window, only floating window would remain")); 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(= N_( "E1155: Cannot define autocommands for ALL events")); diff --git a/test/functional/vimscript/executable_spec.lua b/test/functional/vimscript/executable_spec.lua index 28aefb72e5..048a65188d 100644 --- a/test/functional/vimscript/executable_spec.lua +++ b/test/functional/vimscript/executable_spec.lua @@ -18,7 +18,7 @@ describe('executable()', function() end) 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..')')) end command('let $PATH = fnamemodify("./test/functional/fixtures/bin", ":p")') @@ -27,6 +27,10 @@ describe('executable()', function() end end) + it('returns 0 for empty strings', function() + eq(0, call('executable', '""')) + end) + it('returns 0 for non-existent files', function() eq(0, call('executable', 'no_such_file_exists_209ufq23f')) end) diff --git a/test/functional/vimscript/exepath_spec.lua b/test/functional/vimscript/exepath_spec.lua index 08d2c59af8..bbca954511 100644 --- a/test/functional/vimscript/exepath_spec.lua +++ b/test/functional/vimscript/exepath_spec.lua @@ -20,9 +20,10 @@ describe('exepath()', function() end) 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..')')) end + eq('Vim(call):E1142: Non-empty string required', exc_exec('call exepath("")')) command('let $PATH = fnamemodify("./test/functional/fixtures/bin", ":p")') for _, input in ipairs({'v:null', 'v:true', 'v:false'}) do eq('Vim(call):E928: String required', exc_exec('call exepath('..input..')')) diff --git a/test/functional/vimscript/null_spec.lua b/test/functional/vimscript/null_spec.lua index 7ecbcd2fd6..f23f00bcc5 100644 --- a/test/functional/vimscript/null_spec.lua +++ b/test/functional/vimscript/null_spec.lua @@ -161,7 +161,7 @@ describe('NULL', function() null_test('does not crash :echomsg', 'echomsg S', 0) null_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('does not crash filereadable()', 'filereadable(S)', 0, 0) null_expr_test('does not crash filewritable()', 'filewritable(S)', 0, 0) |