Problem: Ubsan reports errors for integer overflow.
Solution: Define macros for minimum and maximum values. Select an
expression based on the value. (Mike Williams)
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;
/* 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;
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;
/* 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;
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;
{
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;
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
}
}
# 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
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))
static int included_patches[] =
{ /* Add new patch number below this line */
+/**/
+ 219,
/**/
218,
/**/