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

Anthony Ramine n.oxyde@REDACTED
Mon Aug 4 12:28:59 CEST 2014


There is also https://github.com/erlang/otp/pull/388

-- 
Anthony Ramine

Le 4 août 2014 à 12:09, Lukas Larsson <lukas@REDACTED> a écrit :

> 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
>> 
> 
> _______________________________________________
> erlang-bugs mailing list
> erlang-bugs@REDACTED
> http://erlang.org/mailman/listinfo/erlang-bugs




More information about the erlang-bugs mailing list