patch 8.1.0048: vim_str2nr() does not handle numbers close to the maximum
Problem: vim_str2nr() does not handle numbers close to the maximum.
Solution: Check for overflow more precisely. (Ken Takata, closes #2746)
diff --git a/src/charset.c b/src/charset.c
index e6657ce..179fc89 100644
--- a/src/charset.c
+++ b/src/charset.c
@@ -1928,8 +1928,8 @@
while ('0' <= *ptr && *ptr <= '1')
{
/* avoid ubsan error for overflow */
- if (un < UVARNUM_MAX / 2)
- un = 2 * un + (unsigned long)(*ptr - '0');
+ if (un <= UVARNUM_MAX / 2)
+ un = 2 * un + (uvarnumber_T)(*ptr - '0');
else
un = UVARNUM_MAX;
++ptr;
@@ -1943,7 +1943,7 @@
while ('0' <= *ptr && *ptr <= '7')
{
/* avoid ubsan error for overflow */
- if (un < UVARNUM_MAX / 8)
+ if (un <= UVARNUM_MAX / 8)
un = 8 * un + (uvarnumber_T)(*ptr - '0');
else
un = UVARNUM_MAX;
@@ -1960,7 +1960,7 @@
while (vim_isxdigit(*ptr))
{
/* avoid ubsan error for overflow */
- if (un < UVARNUM_MAX / 16)
+ if (un <= UVARNUM_MAX / 16)
un = 16 * un + (uvarnumber_T)hex2nr(*ptr);
else
un = UVARNUM_MAX;
@@ -1974,9 +1974,12 @@
/* decimal */
while (VIM_ISDIGIT(*ptr))
{
+ uvarnumber_T digit = (uvarnumber_T)(*ptr - '0');
+
/* avoid ubsan error for overflow */
- if (un < UVARNUM_MAX / 10)
- un = 10 * un + (uvarnumber_T)(*ptr - '0');
+ if (un < UVARNUM_MAX / 10
+ || (un == UVARNUM_MAX / 10 && digit <= UVARNUM_MAX % 10))
+ un = 10 * un + digit;
else
un = UVARNUM_MAX;
++ptr;