From f2b26bcf8f498fed72759af4aa768fb2aab3118c Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 30 Jan 2021 23:05:11 +0100 Subject: patch 8.2.2434: Vim9: no error when compiling str2nr() with a number Problem: Vim9: no error when compiling str2nr() with a number. Solution: Add argument type checks. (closes #7759) --- src/evalfunc.c | 17 +++++++++++++++-- src/proto/typval.pro | 2 ++ src/testdir/test_vim9_builtin.vim | 7 +++++++ src/typval.c | 24 ++++++++++++++++++++++++ src/version.c | 2 ++ 5 files changed, 50 insertions(+), 2 deletions(-) diff --git a/src/evalfunc.c b/src/evalfunc.c index b752c51d1..1fad082ac 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -330,6 +330,18 @@ arg_string(type_T *type, argcontext_T *context) return check_arg_type(&t_string, type, context); } +/* + * Check "type" is a bool or number 0 or 1. + */ + static int +arg_bool(type_T *type, argcontext_T *context) +{ + if (type->tt_type == VAR_ANY + || type->tt_type == VAR_NUMBER || type->tt_type == VAR_BOOL) + return OK; + return check_arg_type(&t_bool, type, context); +} + /* * Check "type" is a list or a blob. */ @@ -423,6 +435,7 @@ arg_extend3(type_T *type, argcontext_T *context) /* * Lists of functions that check the argument types of a builtin function. */ +argcheck_T arg3_string_nr_bool[] = {arg_string, arg_number, arg_bool}; argcheck_T arg1_float_or_nr[] = {arg_float_or_nr}; argcheck_T arg2_listblob_item[] = {arg_list_or_blob, arg_item_of_prev}; argcheck_T arg23_extend[] = {arg_list_or_dict, arg_same_as_prev, arg_extend3}; @@ -1552,7 +1565,7 @@ static funcentry_T global_functions[] = ret_float, FLOAT_FUNC(f_str2float)}, {"str2list", 1, 2, FEARG_1, NULL, ret_list_number, f_str2list}, - {"str2nr", 1, 3, FEARG_1, NULL, + {"str2nr", 1, 3, FEARG_1, arg3_string_nr_bool, ret_number, f_str2nr}, {"strcharpart", 2, 3, FEARG_1, NULL, ret_string, f_strcharpart}, @@ -9076,7 +9089,7 @@ f_str2nr(typval_T *argvars, typval_T *rettv) what |= STR2NR_QUOTE; } - p = skipwhite(tv_get_string(&argvars[0])); + p = skipwhite(tv_get_string_strict(&argvars[0])); isneg = (*p == '-'); if (*p == '+' || *p == '-') p = skipwhite(p + 1); diff --git a/src/proto/typval.pro b/src/proto/typval.pro index 7a65376c6..93eb64f4d 100644 --- a/src/proto/typval.pro +++ b/src/proto/typval.pro @@ -12,9 +12,11 @@ float_T tv_get_float(typval_T *varp); int check_for_string(typval_T *tv); int check_for_nonempty_string(typval_T *tv); char_u *tv_get_string(typval_T *varp); +char_u *tv_get_string_strict(typval_T *varp); char_u *tv_get_string_buf(typval_T *varp, char_u *buf); char_u *tv_get_string_chk(typval_T *varp); char_u *tv_get_string_buf_chk(typval_T *varp, char_u *buf); +char_u *tv_get_string_buf_chk_strict(typval_T *varp, char_u *buf, int strict); char_u *tv_stringify(typval_T *varp, char_u *buf); int tv_check_lock(typval_T *tv, char_u *name, int use_gettext); void copy_tv(typval_T *from, typval_T *to); diff --git a/src/testdir/test_vim9_builtin.vim b/src/testdir/test_vim9_builtin.vim index 776aec0bd..292910016 100644 --- a/src/testdir/test_vim9_builtin.vim +++ b/src/testdir/test_vim9_builtin.vim @@ -867,6 +867,13 @@ enddef def Test_str2nr() str2nr("1'000'000", 10, true)->assert_equal(1000000) + + CheckDefFailure(['echo str2nr(123)'], 'E1013:') + CheckScriptFailure(['vim9script', 'echo str2nr(123)'], 'E1024:') + CheckDefFailure(['echo str2nr("123", "x")'], 'E1013:') + CheckScriptFailure(['vim9script', 'echo str2nr("123", "x")'], 'E1030:') + CheckDefFailure(['echo str2nr("123", 10, "x")'], 'E1013:') + CheckScriptFailure(['vim9script', 'echo str2nr("123", 10, "x")'], 'E1135:') enddef def Test_strchars() diff --git a/src/typval.c b/src/typval.c index 7e4e63d17..b3325b663 100644 --- a/src/typval.c +++ b/src/typval.c @@ -388,6 +388,19 @@ tv_get_string(typval_T *varp) return tv_get_string_buf(varp, mybuf); } +/* + * Like tv_get_string() but don't allow number to string conversion for Vim9. + */ + char_u * +tv_get_string_strict(typval_T *varp) +{ + static char_u mybuf[NUMBUFLEN]; + char_u *res = tv_get_string_buf_chk_strict( + varp, mybuf, in_vim9script()); + + return res != NULL ? res : (char_u *)""; +} + char_u * tv_get_string_buf(typval_T *varp, char_u *buf) { @@ -409,10 +422,21 @@ tv_get_string_chk(typval_T *varp) char_u * tv_get_string_buf_chk(typval_T *varp, char_u *buf) +{ + return tv_get_string_buf_chk_strict(varp, buf, FALSE); +} + + char_u * +tv_get_string_buf_chk_strict(typval_T *varp, char_u *buf, int strict) { switch (varp->v_type) { case VAR_NUMBER: + if (strict) + { + emsg(_(e_using_number_as_string)); + break; + } vim_snprintf((char *)buf, NUMBUFLEN, "%lld", (varnumber_T)varp->vval.v_number); return buf; diff --git a/src/version.c b/src/version.c index 555a2f937..8159289cb 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2434, /**/ 2433, /**/ -- cgit v1.2.1