Skip to content

Commit 7a40ea2

Browse files
committed
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)
1 parent 2b2207b commit 7a40ea2

6 files changed

Lines changed: 59 additions & 31 deletions

File tree

src/charset.c

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1901,7 +1901,11 @@ vim_str2nr(
19011901
n += 2; /* skip over "0b" */
19021902
while ('0' <= *ptr && *ptr <= '1')
19031903
{
1904-
un = 2 * un + (unsigned long)(*ptr - '0');
1904+
/* avoid ubsan error for overflow */
1905+
if (un < UVARNUM_MAX / 2)
1906+
un = 2 * un + (unsigned long)(*ptr - '0');
1907+
else
1908+
un = UVARNUM_MAX;
19051909
++ptr;
19061910
if (n++ == maxlen)
19071911
break;
@@ -1912,7 +1916,11 @@ vim_str2nr(
19121916
/* octal */
19131917
while ('0' <= *ptr && *ptr <= '7')
19141918
{
1915-
un = 8 * un + (uvarnumber_T)(*ptr - '0');
1919+
/* avoid ubsan error for overflow */
1920+
if (un < UVARNUM_MAX / 8)
1921+
un = 8 * un + (uvarnumber_T)(*ptr - '0');
1922+
else
1923+
un = UVARNUM_MAX;
19161924
++ptr;
19171925
if (n++ == maxlen)
19181926
break;
@@ -1925,7 +1933,11 @@ vim_str2nr(
19251933
n += 2; /* skip over "0x" */
19261934
while (vim_isxdigit(*ptr))
19271935
{
1928-
un = 16 * un + (uvarnumber_T)hex2nr(*ptr);
1936+
/* avoid ubsan error for overflow */
1937+
if (un < UVARNUM_MAX / 16)
1938+
un = 16 * un + (uvarnumber_T)hex2nr(*ptr);
1939+
else
1940+
un = UVARNUM_MAX;
19291941
++ptr;
19301942
if (n++ == maxlen)
19311943
break;
@@ -1936,7 +1948,11 @@ vim_str2nr(
19361948
/* decimal */
19371949
while (VIM_ISDIGIT(*ptr))
19381950
{
1939-
un = 10 * un + (uvarnumber_T)(*ptr - '0');
1951+
/* avoid ubsan error for overflow */
1952+
if (un < UVARNUM_MAX / 10)
1953+
un = 10 * un + (uvarnumber_T)(*ptr - '0');
1954+
else
1955+
un = UVARNUM_MAX;
19401956
++ptr;
19411957
if (n++ == maxlen)
19421958
break;
@@ -1950,9 +1966,19 @@ vim_str2nr(
19501966
if (nptr != NULL)
19511967
{
19521968
if (negative) /* account for leading '-' for decimal numbers */
1953-
*nptr = -(varnumber_T)un;
1969+
{
1970+
/* avoid ubsan error for overflow */
1971+
if (un > VARNUM_MAX)
1972+
*nptr = VARNUM_MIN;
1973+
else
1974+
*nptr = -(varnumber_T)un;
1975+
}
19541976
else
1977+
{
1978+
if (un > VARNUM_MAX)
1979+
un = VARNUM_MAX;
19551980
*nptr = (varnumber_T)un;
1981+
}
19561982
}
19571983
if (unptr != NULL)
19581984
*unptr = un;

src/eval.c

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4109,21 +4109,12 @@ eval6(
41094109
{
41104110
if (n2 == 0) /* give an error message? */
41114111
{
4112-
#ifdef FEAT_NUM64
41134112
if (n1 == 0)
4114-
n1 = -0x7fffffffffffffffLL - 1; /* similar to NaN */
4113+
n1 = VARNUM_MIN; /* similar to NaN */
41154114
else if (n1 < 0)
4116-
n1 = -0x7fffffffffffffffLL;
4115+
n1 = -VARNUM_MAX;
41174116
else
4118-
n1 = 0x7fffffffffffffffLL;
4119-
#else
4120-
if (n1 == 0)
4121-
n1 = -0x7fffffffL - 1L; /* similar to NaN */
4122-
else if (n1 < 0)
4123-
n1 = -0x7fffffffL;
4124-
else
4125-
n1 = 0x7fffffffL;
4126-
#endif
4117+
n1 = VARNUM_MAX;
41274118
}
41284119
else
41294120
n1 = n1 / n2;

src/evalfunc.c

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3304,21 +3304,12 @@ f_float2nr(typval_T *argvars, typval_T *rettv)
33043304

33053305
if (get_float_arg(argvars, &f) == OK)
33063306
{
3307-
# ifdef FEAT_NUM64
3308-
if (f < -0x7fffffffffffffffLL)
3309-
rettv->vval.v_number = -0x7fffffffffffffffLL;
3310-
else if (f > 0x7fffffffffffffffLL)
3311-
rettv->vval.v_number = 0x7fffffffffffffffLL;
3307+
if (f < -VARNUM_MAX)
3308+
rettv->vval.v_number = -VARNUM_MAX;
3309+
else if (f > VARNUM_MAX)
3310+
rettv->vval.v_number = VARNUM_MAX;
33123311
else
33133312
rettv->vval.v_number = (varnumber_T)f;
3314-
# else
3315-
if (f < -0x7fffffff)
3316-
rettv->vval.v_number = -0x7fffffff;
3317-
else if (f > 0x7fffffff)
3318-
rettv->vval.v_number = 0x7fffffff;
3319-
else
3320-
rettv->vval.v_number = (varnumber_T)f;
3321-
# endif
33223313
}
33233314
}
33243315

src/structs.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1133,25 +1133,43 @@ typedef long_u hash_T; /* Type for hi_hash */
11331133
# ifdef PROTO
11341134
typedef long varnumber_T;
11351135
typedef unsigned long uvarnumber_T;
1136+
#define VARNUM_MIN LONG_MIN
1137+
#define VARNUM_MAX LONG_MAX
1138+
#define UVARNUM_MAX ULONG_MAX
11361139
# else
11371140
typedef __int64 varnumber_T;
11381141
typedef unsigned __int64 uvarnumber_T;
1142+
#define VARNUM_MIN _I64_MIN
1143+
#define VARNUM_MAX _I64_MAX
1144+
#define UVARNUM_MAX _UI64_MAX
11391145
# endif
11401146
# elif defined(HAVE_STDINT_H)
11411147
typedef int64_t varnumber_T;
11421148
typedef uint64_t uvarnumber_T;
1149+
#define VARNUM_MIN INT64_MIN
1150+
#define VARNUM_MAX INT64_MAX
1151+
#define UVARNUM_MAX UINT64_MAX
11431152
# else
11441153
typedef long varnumber_T;
11451154
typedef unsigned long uvarnumber_T;
1155+
#define VARNUM_MIN LONG_MIN
1156+
#define VARNUM_MAX LONG_MAX
1157+
#define UVARNUM_MAX ULONG_MAX
11461158
# endif
11471159
#else
11481160
/* Use 32-bit Number. */
11491161
# if VIM_SIZEOF_INT <= 3 /* use long if int is smaller than 32 bits */
11501162
typedef long varnumber_T;
11511163
typedef unsigned long uvarnumber_T;
1164+
#define VARNUM_MIN LONG_MIN
1165+
#define VARNUM_MAX LONG_MAX
1166+
#define UVARNUM_MAX ULONG_MAX
11521167
# else
11531168
typedef int varnumber_T;
11541169
typedef unsigned int uvarnumber_T;
1170+
#define VARNUM_MIN INT_MIN
1171+
#define VARNUM_MAX INT_MAX
1172+
#define UVARNUM_MAX UINT_MAX
11551173
# endif
11561174
#endif
11571175

src/testdir/test_viml.vim

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1226,7 +1226,7 @@ func Test_num64()
12261226

12271227
call assert_equal( 9223372036854775807, 1 / 0)
12281228
call assert_equal(-9223372036854775807, -1 / 0)
1229-
call assert_equal(-9223372036854775808, 0 / 0)
1229+
call assert_equal(-9223372036854775807 - 1, 0 / 0)
12301230

12311231
call assert_equal( 0x7FFFffffFFFFffff, float2nr( 1.0e150))
12321232
call assert_equal(-0x7FFFffffFFFFffff, float2nr(-1.0e150))

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -764,6 +764,8 @@ static char *(features[]) =
764764

765765
static int included_patches[] =
766766
{ /* Add new patch number below this line */
767+
/**/
768+
219,
767769
/**/
768770
218,
769771
/**/

0 commit comments

Comments
 (0)