summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2019-05-19 19:59:35 +0200
committerBram Moolenaar <Bram@vim.org>2019-05-19 19:59:35 +0200
commit16e9b85113e0b354ece1cb4f5fcc7866850f3685 (patch)
tree2abe4e3cffe8b0281f0690e5570a47eb2198a826 /src
parentf5842c5a533346c4ff41ff666e465c85f1de35d5 (diff)
downloadvim-git-16e9b85113e0b354ece1cb4f5fcc7866850f3685.tar.gz
patch 8.1.1355: obvious mistakes are accepted as valid expressionsv8.1.1355
Problem: Obvious mistakes are accepted as valid expressions. Solution: Be more strict about parsing numbers. (Yasuhiro Matsumoto, closes #3981)
Diffstat (limited to 'src')
-rw-r--r--src/charset.c31
-rw-r--r--src/eval.c10
-rw-r--r--src/evalfunc.c3
-rw-r--r--src/ex_cmds.c3
-rw-r--r--src/ex_getln.c4
-rw-r--r--src/json.c22
-rw-r--r--src/misc2.c14
-rw-r--r--src/ops.c2
-rw-r--r--src/option.c6
-rw-r--r--src/proto/charset.pro2
-rw-r--r--src/testdir/test_expr.vim11
-rw-r--r--src/testdir/test_json.vim4
-rw-r--r--src/version.c2
13 files changed, 86 insertions, 28 deletions
diff --git a/src/charset.c b/src/charset.c
index 3eb5b5805..cff62e185 100644
--- 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
index c0c6aa7ad..695034899 100644
--- 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 *denote)
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
index 4c02e159b..5631795e3 100644
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -13199,7 +13199,8 @@ f_str2nr(typval_T *argvars, typval_T *rettv)
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
index 964c4556c..ff86d1cd4 100644
--- 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
index f1c30a2d9..ba3dc7358 100644
--- a/src/ex_getln.c
+++ b/src/ex_getln.c
@@ -6470,7 +6470,7 @@ get_list_range(char_u **str, int *num1, int *num2)
*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, int *num2)
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
index 9fb6af0de..8674bf265 100644
--- a/src/json.c
+++ b/src/json.c
@@ -452,7 +452,12 @@ json_decode_string(js_read_T *reader, typval_T *res, int quote)
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, typval_T *res, int quote)
/* 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, typval_T *res, int options)
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
index f9f6bf58e..dac66ffb2 100644
--- 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]))
{
/* <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
diff --git a/src/ops.c b/src/ops.c
index 975a56f37..a989ce211 100644
--- 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
index a9b978079..bfdf71799 100644
--- 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
index bb4132fe7..f60822ef0 100644
--- 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
index 216a00f7d..ccca79270 100644
--- 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 <Char-0b1z> b', 'E474:')
+endfunc
diff --git a/src/testdir/test_json.vim b/src/testdir/test_json.vim
index e16a7f030..8f85a58cf 100644
--- 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
index 6d2416d13..042a8bcd9 100644
--- 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,