forked from aniani/vim
patch 9.0.1380: CTRL-X on 2**64 subtracts two
Problem: CTRL-X on 2**64 subtracts two. (James McCoy) Solution: Correct computation for large number. (closes #12103)
This commit is contained in:
@@ -2138,7 +2138,8 @@ vim_str2nr(
|
|||||||
varnumber_T *nptr, // return: signed result
|
varnumber_T *nptr, // return: signed result
|
||||||
uvarnumber_T *unptr, // return: unsigned result
|
uvarnumber_T *unptr, // return: unsigned result
|
||||||
int maxlen, // max length of string to check
|
int maxlen, // max length of string to check
|
||||||
int strict) // check strictly
|
int strict, // check strictly
|
||||||
|
int *overflow) // when not NULL set to TRUE for overflow
|
||||||
{
|
{
|
||||||
char_u *ptr = start;
|
char_u *ptr = start;
|
||||||
int pre = 0; // default is decimal
|
int pre = 0; // default is decimal
|
||||||
@@ -2209,7 +2210,11 @@ vim_str2nr(
|
|||||||
if (un <= UVARNUM_MAX / 2)
|
if (un <= UVARNUM_MAX / 2)
|
||||||
un = 2 * un + (uvarnumber_T)(*ptr - '0');
|
un = 2 * un + (uvarnumber_T)(*ptr - '0');
|
||||||
else
|
else
|
||||||
|
{
|
||||||
un = UVARNUM_MAX;
|
un = UVARNUM_MAX;
|
||||||
|
if (overflow != NULL)
|
||||||
|
*overflow = TRUE;
|
||||||
|
}
|
||||||
++ptr;
|
++ptr;
|
||||||
if (n++ == maxlen)
|
if (n++ == maxlen)
|
||||||
break;
|
break;
|
||||||
@@ -2234,7 +2239,11 @@ vim_str2nr(
|
|||||||
if (un <= UVARNUM_MAX / 8)
|
if (un <= UVARNUM_MAX / 8)
|
||||||
un = 8 * un + (uvarnumber_T)(*ptr - '0');
|
un = 8 * un + (uvarnumber_T)(*ptr - '0');
|
||||||
else
|
else
|
||||||
|
{
|
||||||
un = UVARNUM_MAX;
|
un = UVARNUM_MAX;
|
||||||
|
if (overflow != NULL)
|
||||||
|
*overflow = TRUE;
|
||||||
|
}
|
||||||
++ptr;
|
++ptr;
|
||||||
if (n++ == maxlen)
|
if (n++ == maxlen)
|
||||||
break;
|
break;
|
||||||
@@ -2258,7 +2267,11 @@ vim_str2nr(
|
|||||||
if (un <= UVARNUM_MAX / 16)
|
if (un <= UVARNUM_MAX / 16)
|
||||||
un = 16 * un + (uvarnumber_T)hex2nr(*ptr);
|
un = 16 * un + (uvarnumber_T)hex2nr(*ptr);
|
||||||
else
|
else
|
||||||
|
{
|
||||||
un = UVARNUM_MAX;
|
un = UVARNUM_MAX;
|
||||||
|
if (overflow != NULL)
|
||||||
|
*overflow = TRUE;
|
||||||
|
}
|
||||||
++ptr;
|
++ptr;
|
||||||
if (n++ == maxlen)
|
if (n++ == maxlen)
|
||||||
break;
|
break;
|
||||||
@@ -2282,7 +2295,11 @@ vim_str2nr(
|
|||||||
|| (un == UVARNUM_MAX / 10 && digit <= UVARNUM_MAX % 10))
|
|| (un == UVARNUM_MAX / 10 && digit <= UVARNUM_MAX % 10))
|
||||||
un = 10 * un + digit;
|
un = 10 * un + digit;
|
||||||
else
|
else
|
||||||
|
{
|
||||||
un = UVARNUM_MAX;
|
un = UVARNUM_MAX;
|
||||||
|
if (overflow != NULL)
|
||||||
|
*overflow = TRUE;
|
||||||
|
}
|
||||||
++ptr;
|
++ptr;
|
||||||
if (n++ == maxlen)
|
if (n++ == maxlen)
|
||||||
break;
|
break;
|
||||||
@@ -2310,7 +2327,11 @@ vim_str2nr(
|
|||||||
{
|
{
|
||||||
// avoid ubsan error for overflow
|
// avoid ubsan error for overflow
|
||||||
if (un > VARNUM_MAX)
|
if (un > VARNUM_MAX)
|
||||||
|
{
|
||||||
*nptr = VARNUM_MIN;
|
*nptr = VARNUM_MIN;
|
||||||
|
if (overflow != NULL)
|
||||||
|
*overflow = TRUE;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
*nptr = -(varnumber_T)un;
|
*nptr = -(varnumber_T)un;
|
||||||
}
|
}
|
||||||
@@ -2318,7 +2339,11 @@ vim_str2nr(
|
|||||||
{
|
{
|
||||||
// prevent a large unsigned number to become negative
|
// prevent a large unsigned number to become negative
|
||||||
if (un > VARNUM_MAX)
|
if (un > VARNUM_MAX)
|
||||||
|
{
|
||||||
un = VARNUM_MAX;
|
un = VARNUM_MAX;
|
||||||
|
if (overflow != NULL)
|
||||||
|
*overflow = TRUE;
|
||||||
|
}
|
||||||
*nptr = (varnumber_T)un;
|
*nptr = (varnumber_T)un;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -511,7 +511,7 @@ ex_sort(exarg_T *eap)
|
|||||||
|
|
||||||
if (sort_nr || sort_flt)
|
if (sort_nr || sort_flt)
|
||||||
{
|
{
|
||||||
// Make sure vim_str2nr doesn't read any digits past the end
|
// Make sure vim_str2nr() doesn't read any digits past the end
|
||||||
// of the match, by temporarily terminating the string there
|
// of the match, by temporarily terminating the string there
|
||||||
s2 = s + end_col;
|
s2 = s + end_col;
|
||||||
c = *s2;
|
c = *s2;
|
||||||
@@ -539,7 +539,7 @@ ex_sort(exarg_T *eap)
|
|||||||
nrs[lnum - eap->line1].st_u.num.is_number = TRUE;
|
nrs[lnum - eap->line1].st_u.num.is_number = TRUE;
|
||||||
vim_str2nr(s, NULL, NULL, sort_what,
|
vim_str2nr(s, NULL, NULL, sort_what,
|
||||||
&nrs[lnum - eap->line1].st_u.num.value,
|
&nrs[lnum - eap->line1].st_u.num.value,
|
||||||
NULL, 0, FALSE);
|
NULL, 0, FALSE, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@@ -4338,7 +4338,7 @@ get_list_range(char_u **str, int *num1, int *num2)
|
|||||||
*str = skipwhite(*str);
|
*str = skipwhite(*str);
|
||||||
if (**str == '-' || vim_isdigit(**str)) // parse "from" part of range
|
if (**str == '-' || vim_isdigit(**str)) // parse "from" part of range
|
||||||
{
|
{
|
||||||
vim_str2nr(*str, NULL, &len, 0, &num, NULL, 0, FALSE);
|
vim_str2nr(*str, NULL, &len, 0, &num, NULL, 0, FALSE, NULL);
|
||||||
*str += len;
|
*str += len;
|
||||||
*num1 = (int)num;
|
*num1 = (int)num;
|
||||||
first = TRUE;
|
first = TRUE;
|
||||||
@@ -4347,7 +4347,7 @@ get_list_range(char_u **str, int *num1, int *num2)
|
|||||||
if (**str == ',') // parse "to" part of range
|
if (**str == ',') // parse "to" part of range
|
||||||
{
|
{
|
||||||
*str = skipwhite(*str + 1);
|
*str = skipwhite(*str + 1);
|
||||||
vim_str2nr(*str, NULL, &len, 0, &num, NULL, 0, FALSE);
|
vim_str2nr(*str, NULL, &len, 0, &num, NULL, 0, FALSE, NULL);
|
||||||
if (len > 0)
|
if (len > 0)
|
||||||
{
|
{
|
||||||
*num2 = (int)num;
|
*num2 = (int)num;
|
||||||
|
@@ -540,7 +540,7 @@ json_decode_string(js_read_T *reader, typval_T *res, int quote)
|
|||||||
nr = 0;
|
nr = 0;
|
||||||
len = 0;
|
len = 0;
|
||||||
vim_str2nr(p + 2, NULL, &len,
|
vim_str2nr(p + 2, NULL, &len,
|
||||||
STR2NR_HEX + STR2NR_FORCE, &nr, NULL, 4, TRUE);
|
STR2NR_HEX + STR2NR_FORCE, &nr, NULL, 4, TRUE, NULL);
|
||||||
if (len == 0)
|
if (len == 0)
|
||||||
{
|
{
|
||||||
if (res != NULL)
|
if (res != NULL)
|
||||||
@@ -556,8 +556,8 @@ json_decode_string(js_read_T *reader, typval_T *res, int quote)
|
|||||||
|
|
||||||
// decode surrogate pair: \ud812\u3456
|
// decode surrogate pair: \ud812\u3456
|
||||||
len = 0;
|
len = 0;
|
||||||
vim_str2nr(p + 2, NULL, &len,
|
vim_str2nr(p + 2, NULL, &len, STR2NR_HEX + STR2NR_FORCE,
|
||||||
STR2NR_HEX + STR2NR_FORCE, &nr2, NULL, 4, TRUE);
|
&nr2, NULL, 4, TRUE, NULL);
|
||||||
if (len == 0)
|
if (len == 0)
|
||||||
{
|
{
|
||||||
if (res != NULL)
|
if (res != NULL)
|
||||||
@@ -882,7 +882,7 @@ json_decode_item(js_read_T *reader, typval_T *res, int options)
|
|||||||
|
|
||||||
vim_str2nr(reader->js_buf + reader->js_used,
|
vim_str2nr(reader->js_buf + reader->js_used,
|
||||||
NULL, &len, 0, // what
|
NULL, &len, 0, // what
|
||||||
&nr, NULL, 0, TRUE);
|
&nr, NULL, 0, TRUE, NULL);
|
||||||
if (len == 0)
|
if (len == 0)
|
||||||
{
|
{
|
||||||
semsg(_(e_json_decode_error_at_str), p);
|
semsg(_(e_json_decode_error_at_str), p);
|
||||||
|
@@ -1410,7 +1410,7 @@ find_special_key(
|
|||||||
bp += 3; // skip t_xx, xx may be '-' or '>'
|
bp += 3; // skip t_xx, xx may be '-' or '>'
|
||||||
else if (STRNICMP(bp, "char-", 5) == 0)
|
else if (STRNICMP(bp, "char-", 5) == 0)
|
||||||
{
|
{
|
||||||
vim_str2nr(bp + 5, NULL, &l, STR2NR_ALL, NULL, NULL, 0, TRUE);
|
vim_str2nr(bp + 5, NULL, &l, STR2NR_ALL, NULL, NULL, 0, TRUE, NULL);
|
||||||
if (l == 0)
|
if (l == 0)
|
||||||
{
|
{
|
||||||
emsg(_(e_invalid_argument));
|
emsg(_(e_invalid_argument));
|
||||||
@@ -1448,7 +1448,7 @@ find_special_key(
|
|||||||
{
|
{
|
||||||
// <Char-123> or <Char-033> or <Char-0x33>
|
// <Char-123> or <Char-033> or <Char-0x33>
|
||||||
vim_str2nr(last_dash + 6, NULL, &l, STR2NR_ALL, NULL,
|
vim_str2nr(last_dash + 6, NULL, &l, STR2NR_ALL, NULL,
|
||||||
&n, 0, TRUE);
|
&n, 0, TRUE, NULL);
|
||||||
if (l == 0)
|
if (l == 0)
|
||||||
{
|
{
|
||||||
emsg(_(e_invalid_argument));
|
emsg(_(e_invalid_argument));
|
||||||
|
15
src/ops.c
15
src/ops.c
@@ -2781,11 +2781,12 @@ do_addsub(
|
|||||||
? (int)STRLEN(ptr) - col
|
? (int)STRLEN(ptr) - col
|
||||||
: length);
|
: length);
|
||||||
|
|
||||||
|
int overflow = FALSE;
|
||||||
vim_str2nr(ptr + col, &pre, &length,
|
vim_str2nr(ptr + col, &pre, &length,
|
||||||
0 + (do_bin ? STR2NR_BIN : 0)
|
0 + (do_bin ? STR2NR_BIN : 0)
|
||||||
+ (do_oct ? STR2NR_OCT : 0)
|
+ (do_oct ? STR2NR_OCT : 0)
|
||||||
+ (do_hex ? STR2NR_HEX : 0),
|
+ (do_hex ? STR2NR_HEX : 0),
|
||||||
NULL, &n, maxlen, FALSE);
|
NULL, &n, maxlen, FALSE, &overflow);
|
||||||
|
|
||||||
// ignore leading '-' for hex and octal and bin numbers
|
// ignore leading '-' for hex and octal and bin numbers
|
||||||
if (pre && negative)
|
if (pre && negative)
|
||||||
@@ -2802,10 +2803,14 @@ do_addsub(
|
|||||||
subtract ^= TRUE;
|
subtract ^= TRUE;
|
||||||
|
|
||||||
oldn = n;
|
oldn = n;
|
||||||
if (subtract)
|
if (!overflow) // if number is too big don't add/subtract
|
||||||
n -= (uvarnumber_T)Prenum1;
|
{
|
||||||
else
|
if (subtract)
|
||||||
n += (uvarnumber_T)Prenum1;
|
n -= (uvarnumber_T)Prenum1;
|
||||||
|
else
|
||||||
|
n += (uvarnumber_T)Prenum1;
|
||||||
|
}
|
||||||
|
|
||||||
// handle wraparound for decimal numbers
|
// handle wraparound for decimal numbers
|
||||||
if (!pre)
|
if (!pre)
|
||||||
{
|
{
|
||||||
|
@@ -2157,7 +2157,7 @@ do_set_option_numeric(
|
|||||||
else if (*arg == '-' || VIM_ISDIGIT(*arg))
|
else if (*arg == '-' || VIM_ISDIGIT(*arg))
|
||||||
{
|
{
|
||||||
// Allow negative (for 'undolevels'), octal and hex numbers.
|
// Allow negative (for 'undolevels'), octal and hex numbers.
|
||||||
vim_str2nr(arg, NULL, &i, STR2NR_ALL, &value, NULL, 0, TRUE);
|
vim_str2nr(arg, NULL, &i, STR2NR_ALL, &value, NULL, 0, TRUE, NULL);
|
||||||
if (i == 0 || (arg[i] != NUL && !VIM_ISWHITE(arg[i])))
|
if (i == 0 || (arg[i] != NUL && !VIM_ISWHITE(arg[i])))
|
||||||
{
|
{
|
||||||
errmsg = e_number_required_after_equal;
|
errmsg = e_number_required_after_equal;
|
||||||
|
@@ -64,7 +64,7 @@ char_u *skiptowhite_esc(char_u *p);
|
|||||||
long getdigits(char_u **pp);
|
long getdigits(char_u **pp);
|
||||||
long getdigits_quoted(char_u **pp);
|
long getdigits_quoted(char_u **pp);
|
||||||
int vim_isblankline(char_u *lbuf);
|
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);
|
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 hex2nr(int c);
|
||||||
int hexhex2nr(char_u *p);
|
int hexhex2nr(char_u *p);
|
||||||
int rem_backslash(char_u *str);
|
int rem_backslash(char_u *str);
|
||||||
|
@@ -1188,7 +1188,7 @@ f_str2nr(typval_T *argvars, typval_T *rettv)
|
|||||||
case 8: what |= STR2NR_OCT + STR2NR_OOCT + STR2NR_FORCE; break;
|
case 8: what |= STR2NR_OCT + STR2NR_OOCT + STR2NR_FORCE; break;
|
||||||
case 16: what |= STR2NR_HEX + STR2NR_FORCE; break;
|
case 16: what |= STR2NR_HEX + STR2NR_FORCE; break;
|
||||||
}
|
}
|
||||||
vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, FALSE);
|
vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, FALSE, NULL);
|
||||||
// Text after the number is silently ignored.
|
// Text after the number is silently ignored.
|
||||||
if (isneg)
|
if (isneg)
|
||||||
rettv->vval.v_number = -n;
|
rettv->vval.v_number = -n;
|
||||||
|
@@ -840,6 +840,22 @@ func Test_increment_unsigned()
|
|||||||
set nrformats-=unsigned
|
set nrformats-=unsigned
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
func Test_in_decrement_large_number()
|
||||||
|
" NOTE: 18446744073709551616 == 2^64
|
||||||
|
call setline(1, '18446744073709551616')
|
||||||
|
exec "norm! gg0\<C-X>"
|
||||||
|
call assert_equal('18446744073709551615', getline(1))
|
||||||
|
|
||||||
|
exec "norm! gg0\<C-X>"
|
||||||
|
call assert_equal('18446744073709551614', getline(1))
|
||||||
|
|
||||||
|
exec "norm! gg0\<C-A>"
|
||||||
|
call assert_equal('18446744073709551615', getline(1))
|
||||||
|
|
||||||
|
exec "norm! gg0\<C-A>"
|
||||||
|
call assert_equal('-18446744073709551615', getline(1))
|
||||||
|
endfunc
|
||||||
|
|
||||||
func Test_normal_increment_with_virtualedit()
|
func Test_normal_increment_with_virtualedit()
|
||||||
set virtualedit=all
|
set virtualedit=all
|
||||||
|
|
||||||
|
@@ -217,7 +217,7 @@ tv_get_bool_or_number_chk(typval_T *varp, int *denote, int want_bool)
|
|||||||
}
|
}
|
||||||
if (varp->vval.v_string != NULL)
|
if (varp->vval.v_string != NULL)
|
||||||
vim_str2nr(varp->vval.v_string, NULL, NULL,
|
vim_str2nr(varp->vval.v_string, NULL, NULL,
|
||||||
STR2NR_ALL, &n, NULL, 0, FALSE);
|
STR2NR_ALL, &n, NULL, 0, FALSE, NULL);
|
||||||
return n;
|
return n;
|
||||||
case VAR_LIST:
|
case VAR_LIST:
|
||||||
emsg(_(e_using_list_as_number));
|
emsg(_(e_using_list_as_number));
|
||||||
@@ -2230,7 +2230,7 @@ eval_number(
|
|||||||
// decimal, hex or octal number
|
// decimal, hex or octal number
|
||||||
vim_str2nr(*arg, NULL, &len, skip_quotes
|
vim_str2nr(*arg, NULL, &len, skip_quotes
|
||||||
? STR2NR_NO_OCT + STR2NR_QUOTE
|
? STR2NR_NO_OCT + STR2NR_QUOTE
|
||||||
: STR2NR_ALL, &n, NULL, 0, TRUE);
|
: STR2NR_ALL, &n, NULL, 0, TRUE, NULL);
|
||||||
if (len == 0)
|
if (len == 0)
|
||||||
{
|
{
|
||||||
if (evaluate)
|
if (evaluate)
|
||||||
|
@@ -695,6 +695,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
1380,
|
||||||
/**/
|
/**/
|
||||||
1379,
|
1379,
|
||||||
/**/
|
/**/
|
||||||
|
Reference in New Issue
Block a user