To: vim_dev@googlegroups.com Subject: Patch 9.0.1380 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 9.0.1380 Problem: CTRL-X on 2**64 subtracts two. (James McCoy) Solution: Correct computation for large number. (closes #12103) Files: src/charset.c, src/proto/charset.pro, src/ex_cmds.c, src/ex_getln.c, src/json.c, src/misc2.c, src/ops.c, src/option.c, src/strings.c, src/typval.c, src/testdir/test_increment.vim *** ../vim-9.0.1379/src/charset.c 2023-02-21 14:27:34.512360384 +0000 --- src/charset.c 2023-03-04 20:39:35.476205644 +0000 *************** *** 2138,2144 **** 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 --- 2138,2145 ---- varnumber_T *nptr, // return: signed result uvarnumber_T *unptr, // return: unsigned result int maxlen, // max length of string to check ! int strict, // check strictly ! int *overflow) // when not NULL set to TRUE for overflow { char_u *ptr = start; int pre = 0; // default is decimal *************** *** 2209,2215 **** --- 2210,2220 ---- if (un <= UVARNUM_MAX / 2) un = 2 * un + (uvarnumber_T)(*ptr - '0'); else + { un = UVARNUM_MAX; + if (overflow != NULL) + *overflow = TRUE; + } ++ptr; if (n++ == maxlen) break; *************** *** 2234,2240 **** --- 2239,2249 ---- if (un <= UVARNUM_MAX / 8) un = 8 * un + (uvarnumber_T)(*ptr - '0'); else + { un = UVARNUM_MAX; + if (overflow != NULL) + *overflow = TRUE; + } ++ptr; if (n++ == maxlen) break; *************** *** 2258,2264 **** --- 2267,2277 ---- if (un <= UVARNUM_MAX / 16) un = 16 * un + (uvarnumber_T)hex2nr(*ptr); else + { un = UVARNUM_MAX; + if (overflow != NULL) + *overflow = TRUE; + } ++ptr; if (n++ == maxlen) break; *************** *** 2282,2288 **** --- 2295,2305 ---- || (un == UVARNUM_MAX / 10 && digit <= UVARNUM_MAX % 10)) un = 10 * un + digit; else + { un = UVARNUM_MAX; + if (overflow != NULL) + *overflow = TRUE; + } ++ptr; if (n++ == maxlen) break; *************** *** 2310,2316 **** --- 2327,2337 ---- { // avoid ubsan error for overflow if (un > VARNUM_MAX) + { *nptr = VARNUM_MIN; + if (overflow != NULL) + *overflow = TRUE; + } else *nptr = -(varnumber_T)un; } *************** *** 2318,2324 **** --- 2339,2349 ---- { // prevent a large unsigned number to become negative if (un > VARNUM_MAX) + { un = VARNUM_MAX; + if (overflow != NULL) + *overflow = TRUE; + } *nptr = (varnumber_T)un; } } *** ../vim-9.0.1379/src/proto/charset.pro 2023-02-16 15:03:08.501667452 +0000 --- src/proto/charset.pro 2023-03-04 20:44:54.984494997 +0000 *************** *** 64,70 **** long getdigits(char_u **pp); long getdigits_quoted(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); --- 64,70 ---- long getdigits(char_u **pp); long getdigits_quoted(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 *overflow); int hex2nr(int c); int hexhex2nr(char_u *p); int rem_backslash(char_u *str); *** ../vim-9.0.1379/src/ex_cmds.c 2023-02-20 12:16:33.328269404 +0000 --- src/ex_cmds.c 2023-03-04 20:40:53.824282930 +0000 *************** *** 511,517 **** if (sort_nr || sort_flt) { ! // Make sure vim_str2nr doesn't read any digits past the end // of the match, by temporarily terminating the string there s2 = s + end_col; c = *s2; --- 511,517 ---- if (sort_nr || sort_flt) { ! // Make sure vim_str2nr() doesn't read any digits past the end // of the match, by temporarily terminating the string there s2 = s + end_col; c = *s2; *************** *** 539,545 **** 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); } } else --- 539,545 ---- 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, NULL); } } else *** ../vim-9.0.1379/src/ex_getln.c 2023-02-20 12:16:33.328269404 +0000 --- src/ex_getln.c 2023-03-04 20:41:05.688294226 +0000 *************** *** 4338,4344 **** *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; --- 4338,4344 ---- *str = skipwhite(*str); if (**str == '-' || vim_isdigit(**str)) // parse "from" part of range { ! vim_str2nr(*str, NULL, &len, 0, &num, NULL, 0, FALSE, NULL); *str += len; *num1 = (int)num; first = TRUE; *************** *** 4347,4353 **** 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; --- 4347,4353 ---- if (**str == ',') // parse "to" part of range { *str = skipwhite(*str + 1); ! vim_str2nr(*str, NULL, &len, 0, &num, NULL, 0, FALSE, NULL); if (len > 0) { *num2 = (int)num; *** ../vim-9.0.1379/src/json.c 2022-12-08 15:32:11.083034191 +0000 --- src/json.c 2023-03-04 20:41:39.344325712 +0000 *************** *** 540,546 **** nr = 0; len = 0; vim_str2nr(p + 2, NULL, &len, ! STR2NR_HEX + STR2NR_FORCE, &nr, NULL, 4, TRUE); if (len == 0) { if (res != NULL) --- 540,546 ---- nr = 0; len = 0; vim_str2nr(p + 2, NULL, &len, ! STR2NR_HEX + STR2NR_FORCE, &nr, NULL, 4, TRUE, NULL); if (len == 0) { if (res != NULL) *************** *** 556,563 **** // decode surrogate pair: \ud812\u3456 len = 0; ! vim_str2nr(p + 2, NULL, &len, ! STR2NR_HEX + STR2NR_FORCE, &nr2, NULL, 4, TRUE); if (len == 0) { if (res != NULL) --- 556,563 ---- // decode surrogate pair: \ud812\u3456 len = 0; ! vim_str2nr(p + 2, NULL, &len, STR2NR_HEX + STR2NR_FORCE, ! &nr2, NULL, 4, TRUE, NULL); if (len == 0) { if (res != NULL) *************** *** 882,888 **** vim_str2nr(reader->js_buf + reader->js_used, NULL, &len, 0, // what ! &nr, NULL, 0, TRUE); if (len == 0) { semsg(_(e_json_decode_error_at_str), p); --- 882,888 ---- vim_str2nr(reader->js_buf + reader->js_used, NULL, &len, 0, // what ! &nr, NULL, 0, TRUE, NULL); if (len == 0) { semsg(_(e_json_decode_error_at_str), p); *** ../vim-9.0.1379/src/misc2.c 2023-02-11 16:15:46.140840726 +0000 --- src/misc2.c 2023-03-04 20:41:54.724339840 +0000 *************** *** 1410,1416 **** 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_invalid_argument)); --- 1410,1416 ---- 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, NULL); if (l == 0) { emsg(_(e_invalid_argument)); *************** *** 1448,1454 **** { // or or vim_str2nr(last_dash + 6, NULL, &l, STR2NR_ALL, NULL, ! &n, 0, TRUE); if (l == 0) { emsg(_(e_invalid_argument)); --- 1448,1454 ---- { // or or vim_str2nr(last_dash + 6, NULL, &l, STR2NR_ALL, NULL, ! &n, 0, TRUE, NULL); if (l == 0) { emsg(_(e_invalid_argument)); *** ../vim-9.0.1379/src/ops.c 2023-02-20 12:16:33.332269406 +0000 --- src/ops.c 2023-03-04 20:43:16.540412494 +0000 *************** *** 2781,2791 **** ? (int)STRLEN(ptr) - col : length); vim_str2nr(ptr + col, &pre, &length, 0 + (do_bin ? STR2NR_BIN : 0) + (do_oct ? STR2NR_OCT : 0) + (do_hex ? STR2NR_HEX : 0), ! NULL, &n, maxlen, FALSE); // ignore leading '-' for hex and octal and bin numbers if (pre && negative) --- 2781,2792 ---- ? (int)STRLEN(ptr) - col : length); + int overflow = FALSE; vim_str2nr(ptr + col, &pre, &length, 0 + (do_bin ? STR2NR_BIN : 0) + (do_oct ? STR2NR_OCT : 0) + (do_hex ? STR2NR_HEX : 0), ! NULL, &n, maxlen, FALSE, &overflow); // ignore leading '-' for hex and octal and bin numbers if (pre && negative) *************** *** 2802,2811 **** subtract ^= TRUE; oldn = n; ! if (subtract) ! n -= (uvarnumber_T)Prenum1; ! else ! n += (uvarnumber_T)Prenum1; // handle wraparound for decimal numbers if (!pre) { --- 2803,2816 ---- subtract ^= TRUE; oldn = n; ! if (!overflow) // if number is too big don't add/subtract ! { ! if (subtract) ! n -= (uvarnumber_T)Prenum1; ! else ! n += (uvarnumber_T)Prenum1; ! } ! // handle wraparound for decimal numbers if (!pre) { *** ../vim-9.0.1379/src/option.c 2023-03-04 19:57:28.342671183 +0000 --- src/option.c 2023-03-04 20:43:32.100425875 +0000 *************** *** 2157,2163 **** else if (*arg == '-' || VIM_ISDIGIT(*arg)) { // 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 = e_number_required_after_equal; --- 2157,2163 ---- else if (*arg == '-' || VIM_ISDIGIT(*arg)) { // Allow negative (for 'undolevels'), octal and hex numbers. ! vim_str2nr(arg, NULL, &i, STR2NR_ALL, &value, NULL, 0, TRUE, NULL); if (i == 0 || (arg[i] != NUL && !VIM_ISWHITE(arg[i]))) { errmsg = e_number_required_after_equal; *** ../vim-9.0.1379/src/strings.c 2023-01-23 20:46:16.166493150 +0000 --- src/strings.c 2023-03-04 20:43:37.844430785 +0000 *************** *** 1188,1194 **** case 8: what |= STR2NR_OCT + STR2NR_OOCT + STR2NR_FORCE; break; case 16: what |= STR2NR_HEX + STR2NR_FORCE; break; } ! vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, FALSE); // Text after the number is silently ignored. if (isneg) rettv->vval.v_number = -n; --- 1188,1194 ---- case 8: what |= STR2NR_OCT + STR2NR_OOCT + STR2NR_FORCE; break; case 16: what |= STR2NR_HEX + STR2NR_FORCE; break; } ! vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, FALSE, NULL); // Text after the number is silently ignored. if (isneg) rettv->vval.v_number = -n; *** ../vim-9.0.1379/src/typval.c 2023-01-25 21:05:35.131042802 +0000 --- src/typval.c 2023-03-04 20:43:56.792446834 +0000 *************** *** 217,223 **** } 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(_(e_using_list_as_number)); --- 217,223 ---- } if (varp->vval.v_string != NULL) vim_str2nr(varp->vval.v_string, NULL, NULL, ! STR2NR_ALL, &n, NULL, 0, FALSE, NULL); return n; case VAR_LIST: emsg(_(e_using_list_as_number)); *************** *** 2230,2236 **** // decimal, hex or octal number vim_str2nr(*arg, NULL, &len, skip_quotes ? STR2NR_NO_OCT + STR2NR_QUOTE ! : STR2NR_ALL, &n, NULL, 0, TRUE); if (len == 0) { if (evaluate) --- 2230,2236 ---- // decimal, hex or octal number vim_str2nr(*arg, NULL, &len, skip_quotes ? STR2NR_NO_OCT + STR2NR_QUOTE ! : STR2NR_ALL, &n, NULL, 0, TRUE, NULL); if (len == 0) { if (evaluate) *** ../vim-9.0.1379/src/testdir/test_increment.vim 2023-01-28 19:18:56.729720605 +0000 --- src/testdir/test_increment.vim 2023-03-04 20:46:49.696585531 +0000 *************** *** 840,845 **** --- 840,861 ---- set nrformats-=unsigned endfunc + func Test_in_decrement_large_number() + " NOTE: 18446744073709551616 == 2^64 + call setline(1, '18446744073709551616') + exec "norm! gg0\" + call assert_equal('18446744073709551615', getline(1)) + + exec "norm! gg0\" + call assert_equal('18446744073709551614', getline(1)) + + exec "norm! gg0\" + call assert_equal('18446744073709551615', getline(1)) + + exec "norm! gg0\" + call assert_equal('-18446744073709551615', getline(1)) + endfunc + func Test_normal_increment_with_virtualedit() set virtualedit=all *** ../vim-9.0.1379/src/version.c 2023-03-04 19:57:28.342671183 +0000 --- src/version.c 2023-03-04 20:20:43.225852411 +0000 *************** *** 697,698 **** --- 697,700 ---- { /* Add new patch number below this line */ + /**/ + 1380, /**/ -- hundred-and-one symptoms of being an internet addict: 224. You set up your own Web page. You set up a Web page for each of your kids... and your pets. /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// \\\ \\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///