diff options
author | Sean Dewar <seandewar@users.noreply.github.com> | 2021-05-30 22:50:09 +0100 |
---|---|---|
committer | Sean Dewar <seandewar@users.noreply.github.com> | 2021-09-11 15:33:19 +0100 |
commit | 34cb0879551b8217db820f684d913a393f4f38cb (patch) | |
tree | cd8c7320d91be9344cfe859c5861b475c093e565 /src | |
parent | cd18fe17a88d8144e5b841f1ca737fb4adf7885b (diff) | |
download | rneovim-34cb0879551b8217db820f684d913a393f4f38cb.tar.gz rneovim-34cb0879551b8217db820f684d913a393f4f38cb.tar.bz2 rneovim-34cb0879551b8217db820f684d913a393f4f38cb.zip |
vim-patch:8.1.1355: obvious mistakes are accepted as valid expressions
Problem: Obvious mistakes are accepted as valid expressions.
Solution: Be more strict about parsing numbers. (Yasuhiro Matsumoto,
closes vim/vim#3981)
https://github.com/vim/vim/commit/16e9b85113e0b354ece1cb4f5fcc7866850f3685
Update vim_str2nr_spec.lua to add more tests that use strict = true.
Diffstat (limited to 'src')
-rw-r--r-- | src/nvim/charset.c | 18 | ||||
-rw-r--r-- | src/nvim/eval.c | 7 | ||||
-rw-r--r-- | src/nvim/eval/decode.c | 6 | ||||
-rw-r--r-- | src/nvim/eval/funcs.c | 3 | ||||
-rw-r--r-- | src/nvim/eval/typval.c | 3 | ||||
-rw-r--r-- | src/nvim/ex_cmds.c | 2 | ||||
-rw-r--r-- | src/nvim/ex_getln.c | 4 | ||||
-rw-r--r-- | src/nvim/keymap.c | 12 | ||||
-rw-r--r-- | src/nvim/ops.c | 2 | ||||
-rw-r--r-- | src/nvim/option.c | 6 | ||||
-rw-r--r-- | src/nvim/testdir/test_expr.vim | 11 | ||||
-rw-r--r-- | src/nvim/viml/parser/expressions.c | 4 |
12 files changed, 59 insertions, 19 deletions
diff --git a/src/nvim/charset.c b/src/nvim/charset.c index 4725c0d08f..9f11e85b01 100644 --- a/src/nvim/charset.c +++ b/src/nvim/charset.c @@ -1397,6 +1397,7 @@ bool vim_isblankline(char_u *lbuf) /// If "what" contains STR2NR_HEX recognize hex numbers. /// If "what" contains STR2NR_FORCE always assume bin/oct/hex. /// If maxlen > 0, check at a maximum maxlen chars. +/// If strict is true, check the number strictly. return *len = 0 if fail. /// /// @param start /// @param prep Returns guessed type of number 0 = decimal, 'x' or 'X' is @@ -1407,9 +1408,12 @@ bool vim_isblankline(char_u *lbuf) /// @param nptr Returns the signed result. /// @param unptr Returns the unsigned result. /// @param maxlen Max length of string to check. +/// @param strict If true, fail if the number has unexpected trailing +/// alpha-numeric chars: *len is set to 0 and nothing else is +/// returned. void vim_str2nr(const char_u *const start, int *const prep, int *const len, const int what, varnumber_T *const nptr, - uvarnumber_T *const unptr, const int maxlen) + uvarnumber_T *const unptr, const int maxlen, const bool strict) FUNC_ATTR_NONNULL_ARG(1) { const char *ptr = (const char *)start; @@ -1419,6 +1423,10 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len, const bool negative = (ptr[0] == '-'); uvarnumber_T un = 0; + if (len != NULL) { + *len = 0; + } + if (negative) { ptr++; } @@ -1492,7 +1500,7 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len, goto vim_str2nr_dec; } - // Do the string-to-numeric conversion "manually" to avoid sscanf quirks. + // Do the conversion manually to avoid sscanf() quirks. abort(); // Should’ve used goto earlier. #define PARSE_NUMBER(base, cond, conv) \ do { \ @@ -1524,6 +1532,12 @@ vim_str2nr_hex: #undef PARSE_NUMBER vim_str2nr_proceed: + // Check for an alpha-numeric character immediately following, that is + // most likely a typo. + if (strict && ptr - (const char *)start != maxlen && ASCII_ISALNUM(*ptr)) { + return; + } + if (prep != NULL) { *prep = pre; } diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 5603fbb082..fbafe42eb2 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -3950,7 +3950,12 @@ static int eval7( rettv->vval.v_float = f; } } else { - vim_str2nr(*arg, NULL, &len, STR2NR_ALL, &n, NULL, 0); + vim_str2nr(*arg, NULL, &len, STR2NR_ALL, &n, NULL, 0, true); + if (len == 0) { + EMSG2(_(e_invexpr2), *arg); + ret = FAIL; + break; + } *arg += len; if (evaluate) { rettv->v_type = VAR_NUMBER; diff --git a/src/nvim/eval/decode.c b/src/nvim/eval/decode.c index bd4dc87d31..89e1f04bfd 100644 --- a/src/nvim/eval/decode.c +++ b/src/nvim/eval/decode.c @@ -437,7 +437,7 @@ static inline int parse_json_string(const char *const buf, const size_t buf_len, t += 4; uvarnumber_T ch; vim_str2nr((char_u *)ubuf, NULL, NULL, - STR2NR_HEX | STR2NR_FORCE, NULL, &ch, 4); + STR2NR_HEX | STR2NR_FORCE, NULL, &ch, 4, true); if (ch == 0) { hasnul = true; } @@ -611,8 +611,8 @@ parse_json_number_check: // Convert integer varnumber_T nr; int num_len; - vim_str2nr((char_u *) s, NULL, &num_len, 0, &nr, NULL, (int) (p - s)); - if ((int) exp_num_len != num_len) { + vim_str2nr((char_u *)s, NULL, &num_len, 0, &nr, NULL, (int)(p - s), true); + if ((int)exp_num_len != num_len) { emsgf(_("E685: internal error: while converting number \"%.*s\" " "to integer vim_str2nr consumed %i bytes in place of %zu"), (int) exp_num_len, s, num_len, exp_num_len); diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 99f9f17e0a..519b268bd1 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -10030,7 +10030,8 @@ static void f_str2nr(typval_T *argvars, typval_T *rettv, FunPtr fptr) what = 0; } } - vim_str2nr(p, NULL, NULL, what, &n, NULL, 0); + vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, false); + // Text after the number is silently ignored. if (isneg) { rettv->vval.v_number = -n; } else { diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c index 5cb0058ec6..22b3bf026b 100644 --- a/src/nvim/eval/typval.c +++ b/src/nvim/eval/typval.c @@ -2990,7 +2990,8 @@ varnumber_T tv_get_number_chk(const typval_T *const tv, bool *const ret_error) case VAR_STRING: { varnumber_T n = 0; if (tv->vval.v_string != NULL) { - vim_str2nr(tv->vval.v_string, NULL, NULL, STR2NR_ALL, &n, NULL, 0); + vim_str2nr(tv->vval.v_string, NULL, NULL, STR2NR_ALL, &n, NULL, 0, + false); } return n; } diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index bd8d3973d5..2ea16f0d50 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -609,7 +609,7 @@ void ex_sort(exarg_T *eap) } else { nrs[lnum - eap->line1].st_u.num.is_number = true; vim_str2nr(s, NULL, NULL, sort_what, - &nrs[lnum - eap->line1].st_u.num.value, NULL, 0); + &nrs[lnum - eap->line1].st_u.num.value, NULL, 0, false); } } else { s = skipwhite(p); diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 0f98c9cd34..b90773ce83 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -6056,7 +6056,7 @@ int get_list_range(char_u **str, int *num1, int *num2) *str = skipwhite(*str); if (**str == '-' || ascii_isdigit(**str)) { // parse "from" part of range - vim_str2nr(*str, NULL, &len, 0, &num, NULL, 0); + vim_str2nr(*str, NULL, &len, 0, &num, NULL, 0, false); *str += len; *num1 = (int)num; first = true; @@ -6064,7 +6064,7 @@ int get_list_range(char_u **str, int *num1, int *num2) *str = skipwhite(*str); if (**str == ',') { // parse "to" part of range *str = skipwhite(*str + 1); - vim_str2nr(*str, NULL, &len, 0, &num, NULL, 0); + vim_str2nr(*str, NULL, &len, 0, &num, NULL, 0, false); if (len > 0) { *num2 = (int)num; *str = skipwhite(*str + len); diff --git a/src/nvim/keymap.c b/src/nvim/keymap.c index 277b9ade89..c6966ff9fa 100644 --- a/src/nvim/keymap.c +++ b/src/nvim/keymap.c @@ -628,7 +628,11 @@ int find_special_key(const char_u **srcp, const size_t src_len, int *const modp, if (end - bp > 3 && bp[0] == 't' && bp[1] == '_') { bp += 3; // skip t_xx, xx may be '-' or '>' } else if (end - bp > 4 && STRNICMP(bp, "char-", 5) == 0) { - vim_str2nr(bp + 5, NULL, &l, STR2NR_ALL, NULL, NULL, 0); + vim_str2nr(bp + 5, NULL, &l, STR2NR_ALL, NULL, NULL, 0, true); + if (l == 0) { + EMSG(_(e_invarg)); + return 0; + } bp += l + 5; break; } @@ -654,7 +658,11 @@ int find_special_key(const char_u **srcp, const size_t src_len, int *const modp, if (STRNICMP(last_dash + 1, "char-", 5) == 0 && ascii_isdigit(last_dash[6])) { // <Char-123> or <Char-033> or <Char-0x33> - vim_str2nr(last_dash + 6, NULL, NULL, STR2NR_ALL, NULL, &n, 0); + vim_str2nr(last_dash + 6, NULL, &l, STR2NR_ALL, NULL, &n, 0, true); + if (l == 0) { + EMSG(_(e_invarg)); + return 0; + } key = (int)n; } else { int off = 1; diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 3f0d85dc88..77432149ce 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -5017,7 +5017,7 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1) 0 + (do_bin ? STR2NR_BIN : 0) + (do_oct ? STR2NR_OCT : 0) + (do_hex ? STR2NR_HEX : 0), - NULL, &n, maxlen); + NULL, &n, maxlen, false); // ignore leading '-' for hex, octal and bin numbers if (pre && negative) { diff --git a/src/nvim/option.c b/src/nvim/option.c index fdfb409c5e..06389c0ef1 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -1276,9 +1276,9 @@ int do_set( } } else if (*arg == '-' || ascii_isdigit(*arg)) { // Allow negative, octal and hex numbers. - vim_str2nr(arg, NULL, &i, STR2NR_ALL, &value, NULL, 0); - if (arg[i] != NUL && !ascii_iswhite(arg[i])) { - errmsg = e_invarg; + vim_str2nr(arg, NULL, &i, STR2NR_ALL, &value, NULL, 0, true); + if (i == 0 || (arg[i] != NUL && !ascii_iswhite(arg[i]))) { + errmsg = (char_u *)N_("E521: Number required after ="); goto skip; } } else { diff --git a/src/nvim/testdir/test_expr.vim b/src/nvim/testdir/test_expr.vim index 0b41a1127a..c49285621a 100644 --- a/src/nvim/testdir/test_expr.vim +++ b/src/nvim/testdir/test_expr.vim @@ -502,6 +502,17 @@ func Test_empty_concatenate() call assert_equal('b', 'b' . 'a'[4:0]) endfunc +func Test_broken_number() + let X = 'bad' + call assert_fails('echo 1X', 'E15:') + call assert_fails('echo 0b1X', 'E15:') + call assert_fails('echo 0b12', 'E15:') + call assert_fails('echo 0x1X', 'E15:') + call assert_fails('echo 011X', 'E15:') + call assert_equal(2, str2nr('2a')) + call assert_fails('inoremap <Char-0b1z> b', 'E474:') +endfunc + func Test_eval_after_if() let s:val = '' func SetVal(x) diff --git a/src/nvim/viml/parser/expressions.c b/src/nvim/viml/parser/expressions.c index e9d82ca87d..f5bd5479c4 100644 --- a/src/nvim/viml/parser/expressions.c +++ b/src/nvim/viml/parser/expressions.c @@ -351,7 +351,7 @@ LexExprToken viml_pexpr_next_token(ParserState *const pstate, const int flags) } if (exp_start) { vim_str2nr(pline.data + exp_start, NULL, NULL, 0, NULL, &exp_part, - (int)(ret.len - exp_start)); + (int)(ret.len - exp_start), false); } if (exp_negative) { exp_part += frac_size; @@ -369,7 +369,7 @@ LexExprToken viml_pexpr_next_token(ParserState *const pstate, const int flags) int len; int prep; vim_str2nr(pline.data, &prep, &len, STR2NR_ALL, NULL, - &ret.data.num.val.integer, (int)pline.size); + &ret.data.num.val.integer, (int)pline.size, false); ret.len = (size_t)len; const uint8_t bases[] = { [0] = 10, |