]> granicus.if.org Git - vim/commitdiff
patch 8.0.0219: ubsan reports errors for overflow v8.0.0219
authorBram Moolenaar <Bram@vim.org>
Sun, 22 Jan 2017 17:34:57 +0000 (18:34 +0100)
committerBram Moolenaar <Bram@vim.org>
Sun, 22 Jan 2017 17:34:57 +0000 (18:34 +0100)
Problem:    Ubsan reports errors for integer overflow.
Solution:   Define macros for minimum and maximum values.  Select an
            expression based on the value. (Mike Williams)

src/charset.c
src/eval.c
src/evalfunc.c
src/structs.h
src/testdir/test_viml.vim
src/version.c

index c3b62590bcc1fc57e649b06b5c921516fe8b6917..c047afec7ff4c0749a619ec181b3d295e5281caf 100644 (file)
@@ -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;
index f70d03b369e9aac58a7b41b0d9ce96d678bad793..5846936cc00ae0abbcde66e2304ca5498effb7f6 100644 (file)
@@ -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;
index da2235455e01d0b7f50e4c7ad9a0c7869a28be46..9ebd2df41dadd9ca7c812ffdd7c843d8eb34cabb 100644 (file)
@@ -3304,21 +3304,12 @@ f_float2nr(typval_T *argvars, typval_T *rettv)
 
     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
     }
 }
 
index 9c0e0468b4b617bbe6b56c5529ec7229c38c81db..af0a6fd2b7ef2d3d9a433fbc5bf6d60bdb44c5c9 100644 (file)
@@ -1133,25 +1133,43 @@ typedef long_u hash_T;          /* Type for hi_hash */
 #  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
 
index cc2303b647278c4c5b6a322346eff092ba3550a4..c4dd036447f418ab3a5c32af94f2f43640f8426a 100644 (file)
@@ -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))
index 286096866e37c4f63b8e8dc672948fe8ce815217..90f056b690ce6d9906b53ab4f6c0eebc9fbaa5c5 100644 (file)
@@ -764,6 +764,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    219,
 /**/
     218,
 /**/