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

Lukas Larsson lukas@REDACTED
Mon Aug 4 12:09:11 CEST 2014


Hello,

I've added fixes for the two places that you have found bugs. I'll see 
if I can find some more errors from the sanitizers.

Lukas
On 21/07/14 00:34, Tuncer Ayaz wrote:
> On Sun, Jul 20, 2014 at 11:56 PM, Tomas Abrahamsson wrote:
>> 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:
> There are more sanitizers you can try out. Usan is comparatively
> low-impact, but the others cause considerable slowdowns, so don't be
> surprised about that. Asan and Tsan are not cheap, but easier to use
> than Valgrind. Also, you can try the same sanitizers with clang, but
> the names might differ.
>
>> 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
> I just tried and found beam/big.c:1548:4, too.
>
>> 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 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".
> _______________________________________________
> erlang-bugs mailing list
> erlang-bugs@REDACTED
> http://erlang.org/mailman/listinfo/erlang-bugs
>




More information about the erlang-bugs mailing list