summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2017-01-22 18:34:57 +0100
committerBram Moolenaar <Bram@vim.org>2017-01-22 18:34:57 +0100
commit7a40ea2138102545848ea86a361f1b8dec7552b5 (patch)
tree28c03360f9bb2de0d7454f50ffccc1f33c75fe54
parent2b2207ba69c6b009e466a36eef0644ca723e16d3 (diff)
downloadvim-git-7a40ea2138102545848ea86a361f1b8dec7552b5.tar.gz
patch 8.0.0219: ubsan reports errors for overflowv8.0.0219
Problem: Ubsan reports errors for integer overflow. Solution: Define macros for minimum and maximum values. Select an expression based on the value. (Mike Williams)
-rw-r--r--src/charset.c36
-rw-r--r--src/eval.c15
-rw-r--r--src/evalfunc.c17
-rw-r--r--src/structs.h18
-rw-r--r--src/testdir/test_viml.vim2
-rw-r--r--src/version.c2
6 files changed, 59 insertions, 31 deletions
diff --git a/src/charset.c b/src/charset.c
index c3b62590b..c047afec7 100644
--- 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
index f70d03b36..5846936cc 100644
--- 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
index da2235455..9ebd2df41 100644
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -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
}
}
diff --git a/src/structs.h b/src/structs.h
index 9c0e0468b..af0a6fd2b 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -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
diff --git a/src/testdir/test_viml.vim b/src/testdir/test_viml.vim
index cc2303b64..c4dd03644 100644
--- 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
index 286096866..90f056b69 100644
--- 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,