[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