[erlang-bugs] enif_make_int64 => -0 for INT64_MIN with gcc 4.9.1

Mikael Pettersson mikpelinux@REDACTED
Fri Aug 15 10:42:26 CEST 2014


Lukas Larsson writes:
 > On 14/08/14 20:06, Tuncer Ayaz wrote:
 > > Just started building maint and I've been seeing this:
 > > beam/bif.c:2824:5: runtime error: signed integer overflow:
 > > 429496729 * 10 cannot be represented in type 'int'
 > >
 > Yeah I saw that one, but since we use n to determine if we are to use i, 
 > i will never be used while overflowed.

That's unfortunately the wrong way to think about signed overflow in C.
It is _never_ about whether the computed value is used or not; the mere
fact that overflow occurred causes undefined behaviour (UB).  Furthermore,
the worst consequence of UB is not that the HW does something wrong, it's
that the compiler(s) can validly assume that UB doesn't occur, and transform
the code accordingly.  And GCC _will_ do that unless you tell it not to.

For this particular spot, the patch I'm using is:

--- otp_src_17.1/erts/emulator/beam/bif.c.~1~   2014-06-23 21:10:57.000000000 +0200
+++ otp_src_17.1/erts/emulator/beam/bif.c       2014-07-24 16:29:42.395034763 +0200
@@ -2767,6 +2767,7 @@ BIF_RETTYPE integer_to_list_1(BIF_ALIST_
 static int do_list_to_integer(Process *p, Eterm orig_list, 
                              Eterm *integer, Eterm *rest)
 {
+     Uint ufixval = 0; /* preliminary value, if it fits in a fixnum */
      Sint i = 0;
      int skip = 0;
      int neg = 0;
@@ -2821,8 +2822,8 @@ static int do_list_to_integer(Process *p
             unsigned_val(CAR(list_val(lst))) > '9') {
             break;
         }
-        i = i * 10;
-        i = i + unsigned_val(CAR(list_val(lst))) - '0';
+        ufixval *= 10;
+        ufixval += unsigned_val(CAR(list_val(lst))) - '0';
         n++;
         lst = CDR(list_val(lst));
         if (is_nil(lst)) {
@@ -2846,8 +2847,8 @@ static int do_list_to_integer(Process *p
       */
 
      if (n <= SMALL_DIGITS) {  /* It must be small */
-        if (neg) i = -i;
-        res = make_small(i);
+        if (neg) ufixval = -ufixval;
+        res = make_small((Sint)ufixval);
      } else {
         lg2 =  (n+1)*230/69+1;
         m  = (lg2+D_EXP-1)/D_EXP; /* number of digits */


/Mikael



More information about the erlang-bugs mailing list