Skip to content

Commit 16e9b85

Browse files
committed
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)
1 parent f5842c5 commit 16e9b85

13 files changed

Lines changed: 86 additions & 28 deletions

File tree

src/charset.c

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1776,25 +1776,30 @@ vim_isblankline(char_u *lbuf)
17761776
* If "what" contains STR2NR_HEX recognize hex numbers
17771777
* If "what" contains STR2NR_FORCE always assume bin/oct/hex.
17781778
* If maxlen > 0, check at a maximum maxlen chars.
1779+
* If strict is TRUE, check the number strictly. return *len = 0 if fail.
17791780
*/
17801781
void
17811782
vim_str2nr(
17821783
char_u *start,
1783-
int *prep, /* return: type of number 0 = decimal, 'x'
1784-
or 'X' is hex, '0' = octal, 'b' or 'B'
1785-
is bin */
1786-
int *len, /* return: detected length of number */
1787-
int what, /* what numbers to recognize */
1788-
varnumber_T *nptr, /* return: signed result */
1789-
uvarnumber_T *unptr, /* return: unsigned result */
1790-
int maxlen) /* max length of string to check */
1784+
int *prep, // return: type of number 0 = decimal, 'x'
1785+
// or 'X' is hex, '0' = octal, 'b' or 'B'
1786+
// is bin
1787+
int *len, // return: detected length of number
1788+
int what, // what numbers to recognize
1789+
varnumber_T *nptr, // return: signed result
1790+
uvarnumber_T *unptr, // return: unsigned result
1791+
int maxlen, // max length of string to check
1792+
int strict) // check strictly
17911793
{
17921794
char_u *ptr = start;
1793-
int pre = 0; /* default is decimal */
1795+
int pre = 0; // default is decimal
17941796
int negative = FALSE;
17951797
uvarnumber_T un = 0;
17961798
int n;
17971799

1800+
if (len != NULL)
1801+
*len = 0;
1802+
17981803
if (ptr[0] == '-')
17991804
{
18001805
negative = TRUE;
@@ -1836,9 +1841,7 @@ vim_str2nr(
18361841
}
18371842
}
18381843

1839-
/*
1840-
* Do the string-to-numeric conversion "manually" to avoid sscanf quirks.
1841-
*/
1844+
// Do the conversion manually to avoid sscanf() quirks.
18421845
n = 1;
18431846
if (pre == 'B' || pre == 'b' || what == STR2NR_BIN + STR2NR_FORCE)
18441847
{
@@ -1907,6 +1910,10 @@ vim_str2nr(
19071910
break;
19081911
}
19091912
}
1913+
// Check for an alpha-numeric character immediately following, that is
1914+
// most likely a typo.
1915+
if (strict && n - 1 != maxlen && ASCII_ISALNUM(*ptr))
1916+
return;
19101917

19111918
if (prep != NULL)
19121919
*prep = pre;

src/eval.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4453,7 +4453,13 @@ eval7(
44534453
else
44544454
{
44554455
// decimal, hex or octal number
4456-
vim_str2nr(*arg, NULL, &len, STR2NR_ALL, &n, NULL, 0);
4456+
vim_str2nr(*arg, NULL, &len, STR2NR_ALL, &n, NULL, 0, TRUE);
4457+
if (len == 0)
4458+
{
4459+
semsg(_(e_invexpr2), *arg);
4460+
ret = FAIL;
4461+
break;
4462+
}
44574463
*arg += len;
44584464
if (evaluate)
44594465
{
@@ -7460,7 +7466,7 @@ tv_get_number_chk(typval_T *varp, int *denote)
74607466
case VAR_STRING:
74617467
if (varp->vval.v_string != NULL)
74627468
vim_str2nr(varp->vval.v_string, NULL, NULL,
7463-
STR2NR_ALL, &n, NULL, 0);
7469+
STR2NR_ALL, &n, NULL, 0, FALSE);
74647470
return n;
74657471
case VAR_LIST:
74667472
emsg(_("E745: Using a List as a Number"));

src/evalfunc.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13199,7 +13199,8 @@ f_str2nr(typval_T *argvars, typval_T *rettv)
1319913199
case 16: what = STR2NR_HEX + STR2NR_FORCE; break;
1320013200
default: what = 0;
1320113201
}
13202-
vim_str2nr(p, NULL, NULL, what, &n, NULL, 0);
13202+
vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, FALSE);
13203+
// Text after the number is silently ignored.
1320313204
if (isneg)
1320413205
rettv->vval.v_number = -n;
1320513206
else

src/ex_cmds.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -558,7 +558,8 @@ ex_sort(exarg_T *eap)
558558
{
559559
nrs[lnum - eap->line1].st_u.num.is_number = TRUE;
560560
vim_str2nr(s, NULL, NULL, sort_what,
561-
&nrs[lnum - eap->line1].st_u.num.value, NULL, 0);
561+
&nrs[lnum - eap->line1].st_u.num.value,
562+
NULL, 0, FALSE);
562563
}
563564
}
564565
#ifdef FEAT_FLOAT

src/ex_getln.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6470,7 +6470,7 @@ get_list_range(char_u **str, int *num1, int *num2)
64706470
*str = skipwhite(*str);
64716471
if (**str == '-' || vim_isdigit(**str)) /* parse "from" part of range */
64726472
{
6473-
vim_str2nr(*str, NULL, &len, 0, &num, NULL, 0);
6473+
vim_str2nr(*str, NULL, &len, 0, &num, NULL, 0, FALSE);
64746474
*str += len;
64756475
*num1 = (int)num;
64766476
first = TRUE;
@@ -6479,7 +6479,7 @@ get_list_range(char_u **str, int *num1, int *num2)
64796479
if (**str == ',') /* parse "to" part of range */
64806480
{
64816481
*str = skipwhite(*str + 1);
6482-
vim_str2nr(*str, NULL, &len, 0, &num, NULL, 0);
6482+
vim_str2nr(*str, NULL, &len, 0, &num, NULL, 0, FALSE);
64836483
if (len > 0)
64846484
{
64856485
*num2 = (int)num;

src/json.c

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -452,7 +452,12 @@ json_decode_string(js_read_T *reader, typval_T *res, int quote)
452452
nr = 0;
453453
len = 0;
454454
vim_str2nr(p + 2, NULL, &len,
455-
STR2NR_HEX + STR2NR_FORCE, &nr, NULL, 4);
455+
STR2NR_HEX + STR2NR_FORCE, &nr, NULL, 4, TRUE);
456+
if (len == 0)
457+
{
458+
ga_clear(&ga);
459+
return FAIL;
460+
}
456461
p += len + 2;
457462
if (0xd800 <= nr && nr <= 0xdfff
458463
&& (int)(reader->js_end - p) >= 6
@@ -463,7 +468,12 @@ json_decode_string(js_read_T *reader, typval_T *res, int quote)
463468
/* decode surrogate pair: \ud812\u3456 */
464469
len = 0;
465470
vim_str2nr(p + 2, NULL, &len,
466-
STR2NR_HEX + STR2NR_FORCE, &nr2, NULL, 4);
471+
STR2NR_HEX + STR2NR_FORCE, &nr2, NULL, 4, TRUE);
472+
if (len == 0)
473+
{
474+
ga_clear(&ga);
475+
return FAIL;
476+
}
467477
if (0xdc00 <= nr2 && nr2 <= 0xdfff)
468478
{
469479
p += len + 2;
@@ -783,7 +793,13 @@ json_decode_item(js_read_T *reader, typval_T *res, int options)
783793

784794
vim_str2nr(reader->js_buf + reader->js_used,
785795
NULL, &len, 0, /* what */
786-
&nr, NULL, 0);
796+
&nr, NULL, 0, TRUE);
797+
if (len == 0)
798+
{
799+
emsg(_(e_invarg));
800+
retval = FAIL;
801+
goto theend;
802+
}
787803
if (cur_item != NULL)
788804
{
789805
cur_item->v_type = VAR_NUMBER;

src/misc2.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2832,7 +2832,12 @@ find_special_key(
28322832
bp += 3; /* skip t_xx, xx may be '-' or '>' */
28332833
else if (STRNICMP(bp, "char-", 5) == 0)
28342834
{
2835-
vim_str2nr(bp + 5, NULL, &l, STR2NR_ALL, NULL, NULL, 0);
2835+
vim_str2nr(bp + 5, NULL, &l, STR2NR_ALL, NULL, NULL, 0, TRUE);
2836+
if (l == 0)
2837+
{
2838+
emsg(_(e_invarg));
2839+
return 0;
2840+
}
28362841
bp += l + 5;
28372842
break;
28382843
}
@@ -2864,7 +2869,12 @@ find_special_key(
28642869
&& VIM_ISDIGIT(last_dash[6]))
28652870
{
28662871
/* <Char-123> or <Char-033> or <Char-0x33> */
2867-
vim_str2nr(last_dash + 6, NULL, NULL, STR2NR_ALL, NULL, &n, 0);
2872+
vim_str2nr(last_dash + 6, NULL, &l, STR2NR_ALL, NULL, &n, 0, TRUE);
2873+
if (l == 0)
2874+
{
2875+
emsg(_(e_invarg));
2876+
return 0;
2877+
}
28682878
key = (int)n;
28692879
}
28702880
else

src/ops.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5794,7 +5794,7 @@ do_addsub(
57945794
0 + (dobin ? STR2NR_BIN : 0)
57955795
+ (dooct ? STR2NR_OCT : 0)
57965796
+ (dohex ? STR2NR_HEX : 0),
5797-
NULL, &n, maxlen);
5797+
NULL, &n, maxlen, FALSE);
57985798

57995799
/* ignore leading '-' for hex and octal and bin numbers */
58005800
if (pre && negative)

src/option.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4762,10 +4762,10 @@ do_set(
47624762
/* Allow negative (for 'undolevels'), octal and
47634763
* hex numbers. */
47644764
vim_str2nr(arg, NULL, &i, STR2NR_ALL,
4765-
&value, NULL, 0);
4766-
if (arg[i] != NUL && !VIM_ISWHITE(arg[i]))
4765+
&value, NULL, 0, TRUE);
4766+
if (i == 0 || (arg[i] != NUL && !VIM_ISWHITE(arg[i])))
47674767
{
4768-
errmsg = e_invarg;
4768+
errmsg = N_("E521: Number required after =");
47694769
goto skip;
47704770
}
47714771
}

src/proto/charset.pro

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ char_u *skiptowhite(char_u *p);
5454
char_u *skiptowhite_esc(char_u *p);
5555
long getdigits(char_u **pp);
5656
int vim_isblankline(char_u *lbuf);
57-
void vim_str2nr(char_u *start, int *prep, int *len, int what, varnumber_T *nptr, uvarnumber_T *unptr, int maxlen);
57+
void vim_str2nr(char_u *start, int *prep, int *len, int what, varnumber_T *nptr, uvarnumber_T *unptr, int maxlen, int strict);
5858
int hex2nr(int c);
5959
int hexhex2nr(char_u *p);
6060
int rem_backslash(char_u *str);

0 commit comments

Comments
 (0)