Mercurial > vim
changeset 10658:77d66e9ac0ab v8.0.0219
patch 8.0.0219: ubsan reports errors for overflow
commit https://github.com/vim/vim/commit/7a40ea2138102545848ea86a361f1b8dec7552b5
Author: Bram Moolenaar <Bram@vim.org>
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)
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Sun, 22 Jan 2017 18:45:04 +0100 |
parents | d4518c5bfd0b |
children | 6e900b249f71 |
files | src/charset.c src/eval.c src/evalfunc.c src/structs.h src/testdir/test_viml.vim src/version.c |
diffstat | 6 files changed, 59 insertions(+), 31 deletions(-) [+] |
line wrap: on
line diff
--- 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;
--- 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;
--- 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 } }
--- 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
--- 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))