mirror of
				https://github.com/neovim/neovim.git
				synced 2025-10-26 12:27:24 +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
	 Fabian
					Fabian