# HG changeset patch # User Bram Moolenaar # Date 1558288809 -7200 # Node ID 77bcb5055feca44b05c47c907c42cf39056b1133 # Parent 033ac0bfd3ba9fbb54c38ed7515a35efa524c25c patch 8.1.1355: obvious mistakes are accepted as valid expressions commit https://github.com/vim/vim/commit/16e9b85113e0b354ece1cb4f5fcc7866850f3685 Author: Bram Moolenaar Date: Sun May 19 19:59:35 2019 +0200 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 #3981) diff --git a/src/charset.c b/src/charset.c --- a/src/charset.c +++ b/src/charset.c @@ -1776,25 +1776,30 @@ 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. */ void vim_str2nr( char_u *start, - int *prep, /* return: type of number 0 = decimal, 'x' - or 'X' is hex, '0' = octal, 'b' or 'B' - is bin */ - int *len, /* return: detected length of number */ - int what, /* what numbers to recognize */ - varnumber_T *nptr, /* return: signed result */ - uvarnumber_T *unptr, /* return: unsigned result */ - int maxlen) /* max length of string to check */ + int *prep, // return: type of number 0 = decimal, 'x' + // or 'X' is hex, '0' = octal, 'b' or 'B' + // is bin + int *len, // return: detected length of number + int what, // what numbers to recognize + varnumber_T *nptr, // return: signed result + uvarnumber_T *unptr, // return: unsigned result + int maxlen, // max length of string to check + int strict) // check strictly { char_u *ptr = start; - int pre = 0; /* default is decimal */ + int pre = 0; // default is decimal int negative = FALSE; uvarnumber_T un = 0; int n; + if (len != NULL) + *len = 0; + if (ptr[0] == '-') { negative = TRUE; @@ -1836,9 +1841,7 @@ vim_str2nr( } } - /* - * Do the string-to-numeric conversion "manually" to avoid sscanf quirks. - */ + // Do the conversion manually to avoid sscanf() quirks. n = 1; if (pre == 'B' || pre == 'b' || what == STR2NR_BIN + STR2NR_FORCE) { @@ -1907,6 +1910,10 @@ vim_str2nr( break; } } + // Check for an alpha-numeric character immediately following, that is + // most likely a typo. + if (strict && n - 1 != maxlen && ASCII_ISALNUM(*ptr)) + return; if (prep != NULL) *prep = pre; diff --git a/src/eval.c b/src/eval.c --- a/src/eval.c +++ b/src/eval.c @@ -4453,7 +4453,13 @@ eval7( else { // decimal, hex or octal number - vim_str2nr(*arg, NULL, &len, STR2NR_ALL, &n, NULL, 0); + vim_str2nr(*arg, NULL, &len, STR2NR_ALL, &n, NULL, 0, TRUE); + if (len == 0) + { + semsg(_(e_invexpr2), *arg); + ret = FAIL; + break; + } *arg += len; if (evaluate) { @@ -7460,7 +7466,7 @@ tv_get_number_chk(typval_T *varp, int *d case VAR_STRING: if (varp->vval.v_string != NULL) vim_str2nr(varp->vval.v_string, NULL, NULL, - STR2NR_ALL, &n, NULL, 0); + STR2NR_ALL, &n, NULL, 0, FALSE); return n; case VAR_LIST: emsg(_("E745: Using a List as a Number")); diff --git a/src/evalfunc.c b/src/evalfunc.c --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -13199,7 +13199,8 @@ f_str2nr(typval_T *argvars, typval_T *re case 16: what = STR2NR_HEX + STR2NR_FORCE; break; default: 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/ex_cmds.c b/src/ex_cmds.c --- a/src/ex_cmds.c +++ b/src/ex_cmds.c @@ -558,7 +558,8 @@ ex_sort(exarg_T *eap) { 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); } } #ifdef FEAT_FLOAT diff --git a/src/ex_getln.c b/src/ex_getln.c --- a/src/ex_getln.c +++ b/src/ex_getln.c @@ -6470,7 +6470,7 @@ get_list_range(char_u **str, int *num1, *str = skipwhite(*str); if (**str == '-' || vim_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; @@ -6479,7 +6479,7 @@ get_list_range(char_u **str, int *num1, 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; diff --git a/src/json.c b/src/json.c --- a/src/json.c +++ b/src/json.c @@ -452,7 +452,12 @@ json_decode_string(js_read_T *reader, ty nr = 0; len = 0; vim_str2nr(p + 2, NULL, &len, - STR2NR_HEX + STR2NR_FORCE, &nr, NULL, 4); + STR2NR_HEX + STR2NR_FORCE, &nr, NULL, 4, TRUE); + if (len == 0) + { + ga_clear(&ga); + return FAIL; + } p += len + 2; if (0xd800 <= nr && nr <= 0xdfff && (int)(reader->js_end - p) >= 6 @@ -463,7 +468,12 @@ json_decode_string(js_read_T *reader, ty /* decode surrogate pair: \ud812\u3456 */ len = 0; vim_str2nr(p + 2, NULL, &len, - STR2NR_HEX + STR2NR_FORCE, &nr2, NULL, 4); + STR2NR_HEX + STR2NR_FORCE, &nr2, NULL, 4, TRUE); + if (len == 0) + { + ga_clear(&ga); + return FAIL; + } if (0xdc00 <= nr2 && nr2 <= 0xdfff) { p += len + 2; @@ -783,7 +793,13 @@ json_decode_item(js_read_T *reader, typv vim_str2nr(reader->js_buf + reader->js_used, NULL, &len, 0, /* what */ - &nr, NULL, 0); + &nr, NULL, 0, TRUE); + if (len == 0) + { + emsg(_(e_invarg)); + retval = FAIL; + goto theend; + } if (cur_item != NULL) { cur_item->v_type = VAR_NUMBER; diff --git a/src/misc2.c b/src/misc2.c --- a/src/misc2.c +++ b/src/misc2.c @@ -2832,7 +2832,12 @@ find_special_key( bp += 3; /* skip t_xx, xx may be '-' or '>' */ else if (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; } @@ -2864,7 +2869,12 @@ find_special_key( && VIM_ISDIGIT(last_dash[6])) { /* or or */ - 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 diff --git a/src/ops.c b/src/ops.c --- a/src/ops.c +++ b/src/ops.c @@ -5794,7 +5794,7 @@ do_addsub( 0 + (dobin ? STR2NR_BIN : 0) + (dooct ? STR2NR_OCT : 0) + (dohex ? STR2NR_HEX : 0), - NULL, &n, maxlen); + NULL, &n, maxlen, FALSE); /* ignore leading '-' for hex and octal and bin numbers */ if (pre && negative) diff --git a/src/option.c b/src/option.c --- a/src/option.c +++ b/src/option.c @@ -4762,10 +4762,10 @@ do_set( /* Allow negative (for 'undolevels'), octal and * hex numbers. */ vim_str2nr(arg, NULL, &i, STR2NR_ALL, - &value, NULL, 0); - if (arg[i] != NUL && !VIM_ISWHITE(arg[i])) + &value, NULL, 0, TRUE); + if (i == 0 || (arg[i] != NUL && !VIM_ISWHITE(arg[i]))) { - errmsg = e_invarg; + errmsg = N_("E521: Number required after ="); goto skip; } } diff --git a/src/proto/charset.pro b/src/proto/charset.pro --- a/src/proto/charset.pro +++ b/src/proto/charset.pro @@ -54,7 +54,7 @@ char_u *skiptowhite(char_u *p); char_u *skiptowhite_esc(char_u *p); long getdigits(char_u **pp); int vim_isblankline(char_u *lbuf); -void vim_str2nr(char_u *start, int *prep, int *len, int what, varnumber_T *nptr, uvarnumber_T *unptr, int maxlen); +void vim_str2nr(char_u *start, int *prep, int *len, int what, varnumber_T *nptr, uvarnumber_T *unptr, int maxlen, int strict); int hex2nr(int c); int hexhex2nr(char_u *p); int rem_backslash(char_u *str); diff --git a/src/testdir/test_expr.vim b/src/testdir/test_expr.vim --- a/src/testdir/test_expr.vim +++ b/src/testdir/test_expr.vim @@ -512,3 +512,14 @@ func Test_empty_concatenate() call assert_equal('b', 'a'[4:0] . 'b') 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 b', 'E474:') +endfunc diff --git a/src/testdir/test_json.vim b/src/testdir/test_json.vim --- a/src/testdir/test_json.vim +++ b/src/testdir/test_json.vim @@ -176,6 +176,10 @@ func Test_json_decode() call assert_fails('call json_decode("{{}:42}")', "E474:") call assert_fails('call json_decode("{[]:42}")', "E474:") + + call assert_fails('call json_decode("\"\\u111Z\"")', 'E474:') + call assert_equal('[😂]', json_decode('"[\uD83D\uDE02]"')) + call assert_equal('a😂b', json_decode('"a\uD83D\uDE02b"')) endfunc let s:jsl5 = '[7,,,]' diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -768,6 +768,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1355, +/**/ 1354, /**/ 1353,