# HG changeset patch # User Christian Brabandt # Date 1485107104 -3600 # Node ID 77d66e9ac0ab1d96e0e31bde1645c1167a273848 # Parent d4518c5bfd0be50ac0b191b044f16a81dfc71475 patch 8.0.0219: ubsan reports errors for overflow commit https://github.com/vim/vim/commit/7a40ea2138102545848ea86a361f1b8dec7552b5 Author: Bram Moolenaar Date: Sun Jan 22 18:34:57 2017 +0100 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) diff --git a/src/charset.c b/src/charset.c --- a/src/charset.c +++ b/src/charset.c @@ -1901,7 +1901,11 @@ vim_str2nr( n += 2; /* skip over "0b" */ 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; if (n++ == maxlen) break; @@ -1912,7 +1916,11 @@ vim_str2nr( /* octal */ 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; if (n++ == maxlen) break; @@ -1925,7 +1933,11 @@ vim_str2nr( n += 2; /* skip over "0x" */ 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; if (n++ == maxlen) break; @@ -1936,7 +1948,11 @@ vim_str2nr( /* decimal */ 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; if (n++ == maxlen) break; @@ -1950,9 +1966,19 @@ vim_str2nr( if (nptr != NULL) { 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 + { + if (un > VARNUM_MAX) + un = VARNUM_MAX; *nptr = (varnumber_T)un; + } } if (unptr != NULL) *unptr = un; diff --git a/src/eval.c b/src/eval.c --- a/src/eval.c +++ b/src/eval.c @@ -4109,21 +4109,12 @@ eval6( { if (n2 == 0) /* give an error message? */ { -#ifdef FEAT_NUM64 if (n1 == 0) - n1 = -0x7fffffffffffffffLL - 1; /* similar to NaN */ + n1 = VARNUM_MIN; /* similar to NaN */ else if (n1 < 0) - n1 = -0x7fffffffffffffffLL; + n1 = -VARNUM_MAX; else - n1 = 0x7fffffffffffffffLL; -#else - if (n1 == 0) - n1 = -0x7fffffffL - 1L; /* similar to NaN */ - else if (n1 < 0) - n1 = -0x7fffffffL; - else - n1 = 0x7fffffffL; -#endif + n1 = VARNUM_MAX; } else n1 = n1 / n2; diff --git a/src/evalfunc.c b/src/evalfunc.c --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -3304,21 +3304,12 @@ f_float2nr(typval_T *argvars, typval_T * if (get_float_arg(argvars, &f) == OK) { -# ifdef FEAT_NUM64 - if (f < -0x7fffffffffffffffLL) - rettv->vval.v_number = -0x7fffffffffffffffLL; - else if (f > 0x7fffffffffffffffLL) - rettv->vval.v_number = 0x7fffffffffffffffLL; + if (f < -VARNUM_MAX) + rettv->vval.v_number = -VARNUM_MAX; + else if (f > VARNUM_MAX) + rettv->vval.v_number = VARNUM_MAX; else 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 } } diff --git a/src/structs.h b/src/structs.h --- a/src/structs.h +++ b/src/structs.h @@ -1133,25 +1133,43 @@ typedef long_u hash_T; /* Type for hi_h # ifdef PROTO typedef long varnumber_T; typedef unsigned long uvarnumber_T; +#define VARNUM_MIN LONG_MIN +#define VARNUM_MAX LONG_MAX +#define UVARNUM_MAX ULONG_MAX # else typedef __int64 varnumber_T; typedef unsigned __int64 uvarnumber_T; +#define VARNUM_MIN _I64_MIN +#define VARNUM_MAX _I64_MAX +#define UVARNUM_MAX _UI64_MAX # endif # elif defined(HAVE_STDINT_H) typedef int64_t varnumber_T; typedef uint64_t uvarnumber_T; +#define VARNUM_MIN INT64_MIN +#define VARNUM_MAX INT64_MAX +#define UVARNUM_MAX UINT64_MAX # else typedef long varnumber_T; typedef unsigned long uvarnumber_T; +#define VARNUM_MIN LONG_MIN +#define VARNUM_MAX LONG_MAX +#define UVARNUM_MAX ULONG_MAX # endif #else /* Use 32-bit Number. */ # if VIM_SIZEOF_INT <= 3 /* use long if int is smaller than 32 bits */ typedef long varnumber_T; typedef unsigned long uvarnumber_T; +#define VARNUM_MIN LONG_MIN +#define VARNUM_MAX LONG_MAX +#define UVARNUM_MAX ULONG_MAX # else typedef int varnumber_T; typedef unsigned int uvarnumber_T; +#define VARNUM_MIN INT_MIN +#define VARNUM_MAX INT_MAX +#define UVARNUM_MAX UINT_MAX # endif #endif diff --git a/src/testdir/test_viml.vim b/src/testdir/test_viml.vim --- a/src/testdir/test_viml.vim +++ b/src/testdir/test_viml.vim @@ -1226,7 +1226,7 @@ func Test_num64() 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)) diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -765,6 +765,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 219, +/**/ 218, /**/ 217,