diff options
author | Ernie Rael <errael@raelity.com> | 2023-12-16 14:03:33 +0100 |
---|---|---|
committer | Christian Brabandt <cb@256bit.org> | 2023-12-16 14:03:33 +0100 |
commit | d8bf87c9fbd92fd6b837446e886d47e557adadbc (patch) | |
tree | 0a3ef3beef2fa291e2851bc5764a7bbb15b99e11 /src/evalfunc.c | |
parent | df12e39b8b9dd39056e22b452276622cb7b617fd (diff) |
patch 9.0.2169: Vim9: builtin funcs may accept a non-valuev9.0.2169
Problem: Vim9: builtin funcs may accept a non-value
Solution: Restrict builtin functions that accept `type`
This PR finishes off detection and prevention of using a type as a
value. It takes care of builtin functions. However there are some
builtin functions, that need to be able to handle types as well as
non-args: instanceof(), type(), typename(), string().
A "bit", FE_X, is added to funcentry_T; when set, the builtin function
can handle a type (class or type-alias) in addition to a value.
Noteworthy change: Discovered that in compile_call() the builtin add()
is compiled inline instead of calling the builtin. Had to add a check
there.
closes: #13688
Signed-off-by: Ernie Rael <errael@raelity.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Diffstat (limited to 'src/evalfunc.c')
-rw-r--r-- | src/evalfunc.c | 75 |
1 files changed, 60 insertions, 15 deletions
diff --git a/src/evalfunc.c b/src/evalfunc.c index a8d8d2c587..f87c08ffc5 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -1651,7 +1651,7 @@ typedef struct char *f_name; // function name char f_min_argc; // minimal number of arguments char f_max_argc; // maximal number of arguments - char f_argtype; // for method: FEARG_ values + char f_argtype; // for method: FEARG_ values; bits FE_ argcheck_T *f_argcheck; // list of functions to check argument types; // use "arg_any" (not NULL) to accept an // argument of any type @@ -1666,10 +1666,12 @@ typedef struct #define VARGS CHAR_MAX // values for f_argtype; zero means it cannot be used as a method -#define FEARG_1 1 // base is the first argument -#define FEARG_2 2 // base is the second argument -#define FEARG_3 3 // base is the third argument -#define FEARG_4 4 // base is the fourth argument +#define FEARG_1 0x01 // base is the first argument +#define FEARG_2 0x02 // base is the second argument +#define FEARG_3 0x03 // base is the third argument +#define FEARG_4 0x04 // base is the fourth argument +#define FEARG_MASK 0x0F // bits in f_argtype used as argument index +#define FE_X 0x10 // builtin accepts a non-value (class, typealias) #if defined(HAVE_MATH_H) # define MATH_FUNC(name) name @@ -2181,7 +2183,7 @@ static funcentry_T global_functions[] = ret_string, f_inputsecret}, {"insert", 2, 3, FEARG_1, arg23_insert, ret_first_arg, f_insert}, - {"instanceof", 2, VARGS, FEARG_1, arg2_instanceof, + {"instanceof", 2, VARGS, FEARG_1|FE_X, arg2_instanceof, ret_bool, f_instanceof}, {"interrupt", 0, 0, 0, NULL, ret_void, f_interrupt}, @@ -2659,7 +2661,7 @@ static funcentry_T global_functions[] = ret_number, f_strgetchar}, {"stridx", 2, 3, FEARG_1, arg3_string_string_number, ret_number, f_stridx}, - {"string", 1, 1, FEARG_1, NULL, + {"string", 1, 1, FEARG_1|FE_X, NULL, ret_string, f_string}, {"strlen", 1, 1, FEARG_1, arg1_string_or_nr, ret_number, f_strlen}, @@ -2821,7 +2823,7 @@ static funcentry_T global_functions[] = ret_void, f_test_option_not_set}, {"test_override", 2, 2, FEARG_2, arg2_string_number, ret_void, f_test_override}, - {"test_refcount", 1, 1, FEARG_1, NULL, + {"test_refcount", 1, 1, FEARG_1|FE_X, NULL, ret_number, f_test_refcount}, {"test_setmouse", 2, 2, 0, arg2_number, ret_void, f_test_setmouse}, @@ -2853,9 +2855,9 @@ static funcentry_T global_functions[] = ret_string, f_trim}, {"trunc", 1, 1, FEARG_1, arg1_float_or_nr, ret_float, f_trunc}, - {"type", 1, 1, FEARG_1, NULL, + {"type", 1, 1, FEARG_1|FE_X, NULL, ret_number, f_type}, - {"typename", 1, 1, FEARG_1, NULL, + {"typename", 1, 1, FEARG_1|FE_X, NULL, ret_string, f_typename}, {"undofile", 1, 1, FEARG_1, arg1_string, ret_string, f_undofile}, @@ -2928,6 +2930,15 @@ static funcentry_T global_functions[] = }; /* + * Return true if specified function allows a type as an argument. + */ + static int +func_allows_type(int idx) +{ + return (global_functions[idx].f_argtype & FE_X) != 0; +} + +/* * Function given to ExpandGeneric() to obtain the list of internal * or user defined function names. */ @@ -3059,6 +3070,15 @@ internal_func_check_arg_types( int argcount, cctx_T *cctx) { + // Some internal functions accept types like Class as arguments. For other + // functions, check the arguments are not types. + if (!(func_allows_type(idx))) + { + for (int i = 0; i < argcount; ++i) + if (check_type_is_value(types[i].type_curr) == FAIL) + return FAIL; + } + argcheck_T *argchecks = global_functions[idx].f_argcheck; if (argchecks == NULL) @@ -3143,7 +3163,7 @@ check_internal_func(int idx, int argcount) else if (argcount > global_functions[idx].f_max_argc) res = FCERR_TOOMANY; else - return global_functions[idx].f_argtype; + return global_functions[idx].f_argtype & FEARG_MASK; name = internal_func_name(idx); if (res == FCERR_TOOMANY) @@ -3153,6 +3173,24 @@ check_internal_func(int idx, int argcount) return -1; } +/* + * Some internal functions accept types like Class as arguments. For other + * functions, check the arguments are not types. + * + * Return OK/FAIL. + */ + static int +check_args_for_type(int idx, int argcount, typval_T *argvars) +{ + if (!func_allows_type(idx)) + { + for (int i = 0; i < argcount; ++i) + if (check_typval_is_value(&argvars[i]) == FAIL) + return FAIL; + } + return OK; +} + funcerror_T call_internal_func( char_u *name, @@ -3169,6 +3207,8 @@ call_internal_func( return FCERR_TOOFEW; if (argcount > global_functions[i].f_max_argc) return FCERR_TOOMANY; + if (check_args_for_type(i, argcount, argvars) == FAIL) + return FCERR_OTHER; argvars[argcount].v_type = VAR_UNKNOWN; global_functions[i].f_func(argvars, rettv); return FCERR_NONE; @@ -3200,14 +3240,16 @@ call_internal_method( fi = find_internal_func(name); if (fi < 0) return FCERR_UNKNOWN; - if (global_functions[fi].f_argtype == 0) + if ((global_functions[fi].f_argtype & FEARG_MASK) == 0) return FCERR_NOTMETHOD; if (argcount + 1 < global_functions[fi].f_min_argc) return FCERR_TOOFEW; if (argcount + 1 > global_functions[fi].f_max_argc) return FCERR_TOOMANY; + if (check_args_for_type(fi, argcount, argvars) == FAIL) + return FCERR_OTHER; - if (global_functions[fi].f_argtype == FEARG_2) + if ((global_functions[fi].f_argtype & FEARG_MASK) == FEARG_2) { if (argcount < 1) return FCERR_TOOFEW; @@ -3218,7 +3260,7 @@ call_internal_method( for (int i = 1; i < argcount; ++i) argv[i + 1] = argvars[i]; } - else if (global_functions[fi].f_argtype == FEARG_3) + else if ((global_functions[fi].f_argtype & FEARG_MASK) == FEARG_3) { if (argcount < 2) return FCERR_TOOFEW; @@ -3230,7 +3272,7 @@ call_internal_method( for (int i = 2; i < argcount; ++i) argv[i + 1] = argvars[i]; } - else if (global_functions[fi].f_argtype == FEARG_4) + else if ((global_functions[fi].f_argtype & FEARG_MASK) == FEARG_4) { if (argcount < 3) return FCERR_TOOFEW; @@ -3252,6 +3294,9 @@ call_internal_method( } argv[argcount + 1].v_type = VAR_UNKNOWN; + if (check_args_for_type(fi, argcount + 1, argv) == FAIL) + return FCERR_OTHER; + global_functions[fi].f_func(argv, rettv); return FCERR_NONE; } |