[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