[erlang-questions] Half word emulators and NIFs

Paul Davis <>
Thu Jun 30 16:37:35 CEST 2011


On Thu, Jun 30, 2011 at 10:27 AM, Sverker Eriksson
<> wrote:
> Sverker Eriksson wrote:
>>
>> Paul Davis wrote:
>>>
>>> On Mon, Jun 27, 2011 at 6:03 AM, Sverker Eriksson
>>> <> wrote:
>>>
>>>>
>>>> Have you tested with a debug built emulator. That may catch faulty NIF
>>>> behaviors earlier. Otherwise if a NIF builds broken terms on the process
>>>> heap it might not be discovered until later when those terms are matched
>>>> or
>>>> maybe garbage collected.
>>>>
>>>> There is no difference to make NIF's for the halfword emulator. Just use
>>>> the
>>>> NIF API as intended and don't cheat (make assumptions about
>>>> sizeof(ERL_NIF_TERM) for example).
>>>>
>>>> /Sverker, Erlang/OTP
>>>>
>>>>
>>>
>>> I've reduced this to a failing test case in the NIF API [1].
>>>
>>> In the end it boils down to these two functions (notice one is int64,
>>> the other not):
>>>
>>> ERL_NIF_TERM
>>> run_test1(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
>>> {
>>>    return enif_make_int64(env, 1);
>>> }
>>>
>>> ERL_NIF_TERM
>>> run_test2(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
>>> {
>>>    return enif_make_int(env, 1);
>>> }
>>>
>>> Test 1 returns a Value V where (V =:= 1) is false, but (V == 1) is
>>> true. The second function returns a value where both comparisons are
>>> true.
>>>
>>> Paolo also found that amusingly this bug disappears at 2^27 as shown by:
>>>
>>> ERL_NIF_TERM
>>> run_test3(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
>>> {
>>>    return enif_make_int64(env, 134217727);
>>> }
>>>
>>> ERL_NIF_TERM
>>> run_test4(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
>>> {
>>>    return enif_make_int64(env, 134217728);
>>> }
>>>
>>> run_test3 returns a value that can't be pattern matched against
>>> 134217727 but test 4 returns a value that can be matched against
>>> 134217728.
>>>
>>> Also, I built R14B03 on Ubuntu 10.04 with this configure:
>>>
>>> ./configure --enable-smp --enable-threads --enable-m64-build
>>> --without-javac --enable-halfword-emulator
>>>
>>> The processors are a pair of dual core Xeon's if that's important at all.
>>>
>>> [1] https://github.com/davisp/halfwordtest
>>>
>>>
>>
>> Very nice trouble shooting. Thank you Paul.
>>
>> It's a halfword-bug affecting:
>> enif_make_int64
>> enif_make_long
>> enif_make_uint64
>> enif_make_ulong
>>
>> for integer values that can fit into 28 bits.
>>
>> What happens is that it makes a bignum even though the value could have
>> fit into a small integer. Small bignums like that are not allowed
>> internally
>> and that's the reason why it behaves so strangely when comparing.
>>
>> I'll be back with a source patch.
>>
>> /Sverker, Erlang/OTP
>>
> Here is a source patch. Only tested on halfword emulator.
>
> diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c
> index 68421b4..d9b1a8e 100644
> --- a/erts/emulator/beam/erl_nif.c
> +++ b/erts/emulator/beam/erl_nif.c
> @@ -833,8 +833,11 @@ ERL_NIF_TERM enif_make_uint(ErlNifEnv* env, unsigned i)
>
> ERL_NIF_TERM enif_make_long(ErlNifEnv* env, long i)
> {
> +    if (IS_SSMALL(i)) {
> +       return make_small(i);
> +    }
> #if SIZEOF_LONG == ERTS_SIZEOF_ETERM
> -    return IS_SSMALL(i) ? make_small(i) : small_to_big(i,
> alloc_heap(env,2));
> +    return small_to_big(i, alloc_heap(env,2));
> #elif SIZEOF_LONG == 8
>    ensure_heap(env,3);
>    return erts_sint64_to_big(i, &env->hp);
> @@ -843,8 +846,11 @@ ERL_NIF_TERM enif_make_long(ErlNifEnv* env, long i)
>
> ERL_NIF_TERM enif_make_ulong(ErlNifEnv* env, unsigned long i)
> {
> +    if (IS_USMALL(0,i)) {
> +       return make_small(i);
> +    }
> #if SIZEOF_LONG == ERTS_SIZEOF_ETERM
> -    return IS_USMALL(0,i) ? make_small(i) :
> uint_to_big(i,alloc_heap(env,2));
> +    return uint_to_big(i,alloc_heap(env,2));
> #elif SIZEOF_LONG == 8
>    ensure_heap(env,3);
>    return erts_uint64_to_big(i, &env->hp);
>
>
>
> /Sverker, Erlang/OTP
>
>

Verified that this makes my earlier tests pass.

Thanks for the quick response!

Paul Davis



More information about the erlang-questions mailing list