To: vim_dev@googlegroups.com Subject: Patch 8.1.1355 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.1.1355 Problem: Obvious mistakes are accepted as valid expressions. Solution: Be more strict about parsing numbers. (Yasuhiro Matsumoto, closes #3981) Files: src/charset.c, src/eval.c, src/evalfunc.c, src/ex_cmds.c, src/ex_getln.c, src/json.c, src/misc2.c, src/ops.c, src/option.c, src/proto/charset.pro, src/testdir/test_expr.vim, src/testdir/test_json.vim *** ../vim-8.1.1354/src/charset.c 2019-03-21 21:45:30.883282076 +0100 --- src/charset.c 2019-05-19 19:02:56.822368539 +0200 *************** *** 1776,1800 **** * 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. */ 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 */ { char_u *ptr = start; ! int pre = 0; /* default is decimal */ int negative = FALSE; uvarnumber_T un = 0; int n; if (ptr[0] == '-') { negative = TRUE; --- 1776,1805 ---- * 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 strict) // check strictly { char_u *ptr = start; ! 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,1844 **** } } ! /* ! * Do the string-to-numeric conversion "manually" to avoid sscanf quirks. ! */ n = 1; if (pre == 'B' || pre == 'b' || what == STR2NR_BIN + STR2NR_FORCE) { --- 1841,1847 ---- } } ! // Do the conversion manually to avoid sscanf() quirks. n = 1; if (pre == 'B' || pre == 'b' || what == STR2NR_BIN + STR2NR_FORCE) { *************** *** 1907,1912 **** --- 1910,1919 ---- 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; *** ../vim-8.1.1354/src/eval.c 2019-05-19 18:41:23.262148495 +0200 --- src/eval.c 2019-05-19 18:53:32.114127645 +0200 *************** *** 4453,4459 **** else { // decimal, hex or octal number ! vim_str2nr(*arg, NULL, &len, STR2NR_ALL, &n, NULL, 0); *arg += len; if (evaluate) { --- 4453,4465 ---- else { // decimal, hex or octal number ! 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,7466 **** case VAR_STRING: if (varp->vval.v_string != NULL) vim_str2nr(varp->vval.v_string, NULL, NULL, ! STR2NR_ALL, &n, NULL, 0); return n; case VAR_LIST: emsg(_("E745: Using a List as a Number")); --- 7466,7472 ---- case VAR_STRING: if (varp->vval.v_string != NULL) vim_str2nr(varp->vval.v_string, NULL, NULL, ! STR2NR_ALL, &n, NULL, 0, FALSE); return n; case VAR_LIST: emsg(_("E745: Using a List as a Number")); *** ../vim-8.1.1354/src/evalfunc.c 2019-05-19 15:27:09.394109547 +0200 --- src/evalfunc.c 2019-05-19 18:53:32.118127617 +0200 *************** *** 13199,13205 **** case 16: what = STR2NR_HEX + STR2NR_FORCE; break; default: what = 0; } ! vim_str2nr(p, NULL, NULL, what, &n, NULL, 0); if (isneg) rettv->vval.v_number = -n; else --- 13199,13206 ---- case 16: what = STR2NR_HEX + STR2NR_FORCE; break; default: what = 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 *** ../vim-8.1.1354/src/ex_cmds.c 2019-05-19 15:19:53.820445439 +0200 --- src/ex_cmds.c 2019-05-19 18:53:32.118127617 +0200 *************** *** 558,564 **** { 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); } } #ifdef FEAT_FLOAT --- 558,565 ---- { 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, FALSE); } } #ifdef FEAT_FLOAT *** ../vim-8.1.1354/src/ex_getln.c 2019-05-09 15:12:45.168723969 +0200 --- src/ex_getln.c 2019-05-19 18:53:32.118127617 +0200 *************** *** 6470,6476 **** *str = skipwhite(*str); if (**str == '-' || vim_isdigit(**str)) /* parse "from" part of range */ { ! vim_str2nr(*str, NULL, &len, 0, &num, NULL, 0); *str += len; *num1 = (int)num; first = TRUE; --- 6470,6476 ---- *str = skipwhite(*str); if (**str == '-' || vim_isdigit(**str)) /* parse "from" part of range */ { ! vim_str2nr(*str, NULL, &len, 0, &num, NULL, 0, FALSE); *str += len; *num1 = (int)num; first = TRUE; *************** *** 6479,6485 **** if (**str == ',') /* parse "to" part of range */ { *str = skipwhite(*str + 1); ! vim_str2nr(*str, NULL, &len, 0, &num, NULL, 0); if (len > 0) { *num2 = (int)num; --- 6479,6485 ---- if (**str == ',') /* parse "to" part of range */ { *str = skipwhite(*str + 1); ! vim_str2nr(*str, NULL, &len, 0, &num, NULL, 0, FALSE); if (len > 0) { *num2 = (int)num; *** ../vim-8.1.1354/src/json.c 2019-04-12 21:19:01.265386241 +0200 --- src/json.c 2019-05-19 18:53:32.118127617 +0200 *************** *** 452,458 **** nr = 0; len = 0; vim_str2nr(p + 2, NULL, &len, ! STR2NR_HEX + STR2NR_FORCE, &nr, NULL, 4); p += len + 2; if (0xd800 <= nr && nr <= 0xdfff && (int)(reader->js_end - p) >= 6 --- 452,463 ---- nr = 0; len = 0; vim_str2nr(p + 2, NULL, &len, ! 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,469 **** /* decode surrogate pair: \ud812\u3456 */ len = 0; vim_str2nr(p + 2, NULL, &len, ! STR2NR_HEX + STR2NR_FORCE, &nr2, NULL, 4); if (0xdc00 <= nr2 && nr2 <= 0xdfff) { p += len + 2; --- 468,479 ---- /* decode surrogate pair: \ud812\u3456 */ len = 0; vim_str2nr(p + 2, NULL, &len, ! 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,789 **** vim_str2nr(reader->js_buf + reader->js_used, NULL, &len, 0, /* what */ ! &nr, NULL, 0); if (cur_item != NULL) { cur_item->v_type = VAR_NUMBER; --- 793,805 ---- vim_str2nr(reader->js_buf + reader->js_used, NULL, &len, 0, /* what */ ! &nr, NULL, 0, TRUE); ! if (len == 0) ! { ! emsg(_(e_invarg)); ! retval = FAIL; ! goto theend; ! } if (cur_item != NULL) { cur_item->v_type = VAR_NUMBER; *** ../vim-8.1.1354/src/misc2.c 2019-05-09 15:12:45.172723940 +0200 --- src/misc2.c 2019-05-19 18:53:32.118127617 +0200 *************** *** 2832,2838 **** 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); bp += l + 5; break; } --- 2832,2843 ---- 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, TRUE); ! if (l == 0) ! { ! emsg(_(e_invarg)); ! return 0; ! } bp += l + 5; break; } *************** *** 2864,2870 **** && VIM_ISDIGIT(last_dash[6])) { /* or or */ ! vim_str2nr(last_dash + 6, NULL, NULL, STR2NR_ALL, NULL, &n, 0); key = (int)n; } else --- 2869,2880 ---- && VIM_ISDIGIT(last_dash[6])) { /* or or */ ! 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 *** ../vim-8.1.1354/src/ops.c 2019-05-19 15:19:53.824445415 +0200 --- src/ops.c 2019-05-19 18:53:32.122127587 +0200 *************** *** 5794,5800 **** 0 + (dobin ? STR2NR_BIN : 0) + (dooct ? STR2NR_OCT : 0) + (dohex ? STR2NR_HEX : 0), ! NULL, &n, maxlen); /* ignore leading '-' for hex and octal and bin numbers */ if (pre && negative) --- 5794,5800 ---- 0 + (dobin ? STR2NR_BIN : 0) + (dooct ? STR2NR_OCT : 0) + (dohex ? STR2NR_HEX : 0), ! NULL, &n, maxlen, FALSE); /* ignore leading '-' for hex and octal and bin numbers */ if (pre && negative) *** ../vim-8.1.1354/src/option.c 2019-05-09 15:12:45.176723907 +0200 --- src/option.c 2019-05-19 18:53:32.122127587 +0200 *************** *** 4762,4771 **** /* 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])) { ! errmsg = e_invarg; goto skip; } } --- 4762,4771 ---- /* Allow negative (for 'undolevels'), octal and * hex numbers. */ vim_str2nr(arg, NULL, &i, STR2NR_ALL, ! &value, NULL, 0, TRUE); ! if (i == 0 || (arg[i] != NUL && !VIM_ISWHITE(arg[i]))) { ! errmsg = N_("E521: Number required after ="); goto skip; } } *** ../vim-8.1.1354/src/proto/charset.pro 2018-05-17 13:52:29.000000000 +0200 --- src/proto/charset.pro 2019-05-19 18:53:32.122127587 +0200 *************** *** 54,60 **** 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); int hex2nr(int c); int hexhex2nr(char_u *p); int rem_backslash(char_u *str); --- 54,60 ---- 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, int strict); int hex2nr(int c); int hexhex2nr(char_u *p); int rem_backslash(char_u *str); *** ../vim-8.1.1354/src/testdir/test_expr.vim 2018-12-15 16:08:52.998468517 +0100 --- src/testdir/test_expr.vim 2019-05-19 18:57:21.312514000 +0200 *************** *** 512,514 **** --- 512,525 ---- 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 *** ../vim-8.1.1354/src/testdir/test_json.vim 2019-04-12 21:19:01.265386241 +0200 --- src/testdir/test_json.vim 2019-05-19 18:53:32.122127587 +0200 *************** *** 176,181 **** --- 176,185 ---- 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,,,]' *** ../vim-8.1.1354/src/version.c 2019-05-19 18:41:23.262148495 +0200 --- src/version.c 2019-05-19 18:56:01.189060580 +0200 *************** *** 769,770 **** --- 769,772 ---- { /* Add new patch number below this line */ + /**/ + 1355, /**/ -- Bad fashion can discourage normal people from interacting with the engineer and talking about the cute things their children do. (Scott Adams - The Dilbert principle) /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///