[erlang-bugs] enif_make_int64 => -0 for INT64_MIN with gcc 4.9.1
Tuncer Ayaz
tuncer.ayaz@REDACTED
Mon Jul 21 00:34:25 CEST 2014
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".
More information about the erlang-bugs
mailing list