[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