1
0
forked from aniani/vim

patch 8.0.0219: ubsan reports errors for overflow

Problem:    Ubsan reports errors for integer overflow.
Solution:   Define macros for minimum and maximum values.  Select an
            expression based on the value. (Mike Williams)
This commit is contained in:
Bram Moolenaar
2017-01-22 18:34:57 +01:00
parent 2b2207ba69
commit 7a40ea2138
6 changed files with 59 additions and 31 deletions

View File

@@ -1901,7 +1901,11 @@ vim_str2nr(
n += 2; /* skip over "0b" */ n += 2; /* skip over "0b" */
while ('0' <= *ptr && *ptr <= '1') while ('0' <= *ptr && *ptr <= '1')
{ {
un = 2 * un + (unsigned long)(*ptr - '0'); /* avoid ubsan error for overflow */
if (un < UVARNUM_MAX / 2)
un = 2 * un + (unsigned long)(*ptr - '0');
else
un = UVARNUM_MAX;
++ptr; ++ptr;
if (n++ == maxlen) if (n++ == maxlen)
break; break;
@@ -1912,7 +1916,11 @@ vim_str2nr(
/* octal */ /* octal */
while ('0' <= *ptr && *ptr <= '7') while ('0' <= *ptr && *ptr <= '7')
{ {
un = 8 * un + (uvarnumber_T)(*ptr - '0'); /* avoid ubsan error for overflow */
if (un < UVARNUM_MAX / 8)
un = 8 * un + (uvarnumber_T)(*ptr - '0');
else
un = UVARNUM_MAX;
++ptr; ++ptr;
if (n++ == maxlen) if (n++ == maxlen)
break; break;
@@ -1925,7 +1933,11 @@ vim_str2nr(
n += 2; /* skip over "0x" */ n += 2; /* skip over "0x" */
while (vim_isxdigit(*ptr)) while (vim_isxdigit(*ptr))
{ {
un = 16 * un + (uvarnumber_T)hex2nr(*ptr); /* avoid ubsan error for overflow */
if (un < UVARNUM_MAX / 16)
un = 16 * un + (uvarnumber_T)hex2nr(*ptr);
else
un = UVARNUM_MAX;
++ptr; ++ptr;
if (n++ == maxlen) if (n++ == maxlen)
break; break;
@@ -1936,7 +1948,11 @@ vim_str2nr(
/* decimal */ /* decimal */
while (VIM_ISDIGIT(*ptr)) while (VIM_ISDIGIT(*ptr))
{ {
un = 10 * un + (uvarnumber_T)(*ptr - '0'); /* avoid ubsan error for overflow */
if (un < UVARNUM_MAX / 10)
un = 10 * un + (uvarnumber_T)(*ptr - '0');
else
un = UVARNUM_MAX;
++ptr; ++ptr;
if (n++ == maxlen) if (n++ == maxlen)
break; break;
@@ -1950,9 +1966,19 @@ vim_str2nr(
if (nptr != NULL) if (nptr != NULL)
{ {
if (negative) /* account for leading '-' for decimal numbers */ if (negative) /* account for leading '-' for decimal numbers */
*nptr = -(varnumber_T)un; {
/* avoid ubsan error for overflow */
if (un > VARNUM_MAX)
*nptr = VARNUM_MIN;
else
*nptr = -(varnumber_T)un;
}
else else
{
if (un > VARNUM_MAX)
un = VARNUM_MAX;
*nptr = (varnumber_T)un; *nptr = (varnumber_T)un;
}
} }
if (unptr != NULL) if (unptr != NULL)
*unptr = un; *unptr = un;

View File

@@ -4109,21 +4109,12 @@ eval6(
{ {
if (n2 == 0) /* give an error message? */ if (n2 == 0) /* give an error message? */
{ {
#ifdef FEAT_NUM64
if (n1 == 0) if (n1 == 0)
n1 = -0x7fffffffffffffffLL - 1; /* similar to NaN */ n1 = VARNUM_MIN; /* similar to NaN */
else if (n1 < 0) else if (n1 < 0)
n1 = -0x7fffffffffffffffLL; n1 = -VARNUM_MAX;
else else
n1 = 0x7fffffffffffffffLL; n1 = VARNUM_MAX;
#else
if (n1 == 0)
n1 = -0x7fffffffL - 1L; /* similar to NaN */
else if (n1 < 0)
n1 = -0x7fffffffL;
else
n1 = 0x7fffffffL;
#endif
} }
else else
n1 = n1 / n2; n1 = n1 / n2;

View File

@@ -3304,21 +3304,12 @@ f_float2nr(typval_T *argvars, typval_T *rettv)
if (get_float_arg(argvars, &f) == OK) if (get_float_arg(argvars, &f) == OK)
{ {
# ifdef FEAT_NUM64 if (f < -VARNUM_MAX)
if (f < -0x7fffffffffffffffLL) rettv->vval.v_number = -VARNUM_MAX;
rettv->vval.v_number = -0x7fffffffffffffffLL; else if (f > VARNUM_MAX)
else if (f > 0x7fffffffffffffffLL) rettv->vval.v_number = VARNUM_MAX;
rettv->vval.v_number = 0x7fffffffffffffffLL;
else else
rettv->vval.v_number = (varnumber_T)f; rettv->vval.v_number = (varnumber_T)f;
# else
if (f < -0x7fffffff)
rettv->vval.v_number = -0x7fffffff;
else if (f > 0x7fffffff)
rettv->vval.v_number = 0x7fffffff;
else
rettv->vval.v_number = (varnumber_T)f;
# endif
} }
} }

View File

@@ -1133,25 +1133,43 @@ typedef long_u hash_T; /* Type for hi_hash */
# ifdef PROTO # ifdef PROTO
typedef long varnumber_T; typedef long varnumber_T;
typedef unsigned long uvarnumber_T; typedef unsigned long uvarnumber_T;
#define VARNUM_MIN LONG_MIN
#define VARNUM_MAX LONG_MAX
#define UVARNUM_MAX ULONG_MAX
# else # else
typedef __int64 varnumber_T; typedef __int64 varnumber_T;
typedef unsigned __int64 uvarnumber_T; typedef unsigned __int64 uvarnumber_T;
#define VARNUM_MIN _I64_MIN
#define VARNUM_MAX _I64_MAX
#define UVARNUM_MAX _UI64_MAX
# endif # endif
# elif defined(HAVE_STDINT_H) # elif defined(HAVE_STDINT_H)
typedef int64_t varnumber_T; typedef int64_t varnumber_T;
typedef uint64_t uvarnumber_T; typedef uint64_t uvarnumber_T;
#define VARNUM_MIN INT64_MIN
#define VARNUM_MAX INT64_MAX
#define UVARNUM_MAX UINT64_MAX
# else # else
typedef long varnumber_T; typedef long varnumber_T;
typedef unsigned long uvarnumber_T; typedef unsigned long uvarnumber_T;
#define VARNUM_MIN LONG_MIN
#define VARNUM_MAX LONG_MAX
#define UVARNUM_MAX ULONG_MAX
# endif # endif
#else #else
/* Use 32-bit Number. */ /* Use 32-bit Number. */
# if VIM_SIZEOF_INT <= 3 /* use long if int is smaller than 32 bits */ # if VIM_SIZEOF_INT <= 3 /* use long if int is smaller than 32 bits */
typedef long varnumber_T; typedef long varnumber_T;
typedef unsigned long uvarnumber_T; typedef unsigned long uvarnumber_T;
#define VARNUM_MIN LONG_MIN
#define VARNUM_MAX LONG_MAX
#define UVARNUM_MAX ULONG_MAX
# else # else
typedef int varnumber_T; typedef int varnumber_T;
typedef unsigned int uvarnumber_T; typedef unsigned int uvarnumber_T;
#define VARNUM_MIN INT_MIN
#define VARNUM_MAX INT_MAX
#define UVARNUM_MAX UINT_MAX
# endif # endif
#endif #endif

View File

@@ -1226,7 +1226,7 @@ func Test_num64()
call assert_equal( 9223372036854775807, 1 / 0) call assert_equal( 9223372036854775807, 1 / 0)
call assert_equal(-9223372036854775807, -1 / 0) call assert_equal(-9223372036854775807, -1 / 0)
call assert_equal(-9223372036854775808, 0 / 0) call assert_equal(-9223372036854775807 - 1, 0 / 0)
call assert_equal( 0x7FFFffffFFFFffff, float2nr( 1.0e150)) call assert_equal( 0x7FFFffffFFFFffff, float2nr( 1.0e150))
call assert_equal(-0x7FFFffffFFFFffff, float2nr(-1.0e150)) call assert_equal(-0x7FFFffffFFFFffff, float2nr(-1.0e150))

View File

@@ -764,6 +764,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 */
/**/
219,
/**/ /**/
218, 218,
/**/ /**/