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

Tomas Abrahamsson tomas.abrahamsson@REDACTED
Sun Jul 20 23:56:59 CEST 2014


Hi, that sanitizer branch was most useful! I hope it will make it into erlang.
This is a run of the previous code with the sanitizers merged into OTP-17.1.1:

Erlang/OTP 17 [erts-6.1.2] [source-cc894a7] [smp:4:4]
[async-threads:10] [kernel-poll:false]

beam/utils.c:453:14: runtime error: negation of -9223372036854775808
cannot be represented in type 'long long int'; cast to an unsigned
type to negate this value to itself

beam/big.c:1548:4: runtime error: negation of -9223372036854775808
cannot be represented in type 'long long int'; cast to an unsigned
type to negate this value to itself

The relevant files do indeed look like they are negating INT64_MIN.
(by the way, in utils.c, the erts_bld_sint64 takes else branch,
as expected, but advances szp by 0.)

Cramming in an (unsigned long long int) cast in there
like the sanitizer error says, actually does make it
print -9223372036854775808 in the erlang code,
and no sanitizer error is printed anymore.

  utils.c
   443  Eterm
   444  erts_bld_sint64(Uint **hpp, Uint *szp, Sint64 si64)
   445  {
   446      Eterm res = THE_NON_VALUE;
   447      if (IS_SSMALL(si64)) {
   448          if (hpp)
   449              res = make_small((Sint) si64);
   450      }
   451      else {
   452          if (szp)
   453              *szp += ERTS_SINT64_HEAP_SIZE(si64);
   454          if (hpp)
   455              res = erts_sint64_to_big(si64, hpp);
   456      }
   457      return res;
   458  }

  big.h
   101  #define ERTS_SINT64_HEAP_SIZE(X)                                \
   102    (IS_SSMALL((X))                                               \
   103     ? 0                                                          \
   104     : ERTS_UINT64_BIG_HEAP_SIZE__((X) >= 0 ? (X) : -(X)))

  big.c
  1540  Eterm erts_sint64_to_big(Sint64 x, Eterm **hpp)
  1541  {
  1542      Eterm *hp = *hpp;
  1543      int neg;
  1544      if (x >= 0)
  1545          neg = 0;
  1546      else {
  1547          neg = 1;
  1548          x = -x;
  1549      }
            ...

I tried changing big.h:104 into:
            : ERTS_UINT64_BIG_HEAP_SIZE__((X) >= 0 ? (X) : -((unsigned
long long int)X)))
and big.c:1548 into:
                   x = -(unsigned long long int)x;

This could be an interesting quick check property,
to verify no undefined behaviours for various programs and values.

BRs
Tomas

On Sun, Jul 20, 2014 at 10:00 PM, Tuncer Ayaz <tuncer.ayaz@REDACTED> wrote:
> On Sun, Jul 20, 2014 at 3:27 AM, Tomas Abrahamsson wrote:
>> Hi,
>>
>> I upgraded gcc from version 4.8.1 to 4.9.1, recompiled Erlang/OTP-17.1.1
>> and my nif, and now enif_make_int64 creates -0 for INT64_MIN.
>>
>>   % make test
>>   erl -s int64nif go -s erlang halt
>>   Erlang/OTP 17 [erts-6.1.1] [source] [smp:4:4] [async-threads:10]
>> [kernel-poll:false]
>>
>>   -0
>>
>> When Erlang was compiled with gcc-4.8.1, it printed -9223372036854775808,
>> I've attached the test programs, here are the important lines:
>>
>>     go() ->
>>         io:format("~p~n", [int64_from_nif()]).
>>
>> The NIF C-code contains:
>>
>>     static ERL_NIF_TERM
>>     int64_from_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
>>     {
>>         return enif_make_int64(env, INT64_MIN);
>>     }
>>
>> System information:
>>
>>   OS: linux, 32-bit core i5, 3.14-1-686-pae (debian unstable)
>>   Erlang/OTP: built from scratch (both times) from the OTP-17.1.1 git tag.
>>   gcc: initially: gcc (Debian 4.8.1-10) 4.8.1
>>        with this one, it prints -9223372036854775808
>>   gcc: after upgrade: gcc (Debian 4.9.1-1) 4.9.1
>>        with this one, it prints -0
>>
>> The only change I did was apt-get install gcc and then rebuilding Erlang.
>
> I can confirm this on linux amd64.
>
> 17.1.2  gcc 4.8.2 -> -9223372036854775808
> 17.1.2  gcc 4.9.0 -> -0
> 17.1.2  gcc 4.9.1 -> -0
>
> 16B03-1 gcc 4.8.2 -> -9223372036854775808
> 16B03-1 gcc 4.9.0 -> 0
> 16B03-1 gcc 4.9.1 -> 0
>
>
> I suppose you're not able to distill this to stand-alone C code, right?
>
> I don't think it will reveal anything, but it's an easy way to find
> bugs, so maybe you can try building with -fsanitize=undefined. If you
> want to do that, I'd suggest to apply the patch available at
> https://github.com/erlang/otp/pull/429 and run
> "configure --enable-sanitizers=undefined".



More information about the erlang-bugs mailing list