Skip to content

Commit

Permalink
Fix halfword bug in enif_make_int64
Browse files Browse the repository at this point in the history
The bug was creating an invalid bignum instead of a small integer,
causing strange comparing behavior (=:= failed but == succeeded).
  • Loading branch information
sverker committed Jun 30, 2011
1 parent 7092c4a commit 1c09660
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 5 deletions.
10 changes: 8 additions & 2 deletions erts/emulator/beam/erl_nif.c
Expand Up @@ -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);
Expand All @@ -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);
Expand Down
42 changes: 41 additions & 1 deletion erts/emulator/test/nif_SUITE.erl
Expand Up @@ -257,10 +257,48 @@ types(Config) when is_list(Config) ->
end,
[{},{ok},{{}},{[],{}},{1,2,3,4,5}]),
Stuff = [[],{},0,0.0,(1 bsl 100),(fun()-> ok end),make_ref(),self()],
[eq_cmp(A,clone(B)) || A<-Stuff, B<-Stuff],
[eq_cmp(A,clone(B)) || A<-Stuff, B<-Stuff],

{IntSz, LongSz} = type_sizes(),
UintMax = (1 bsl (IntSz*8)) - 1,
IntMax = UintMax bsr 1,
IntMin = -(IntMax+1),
UlongMax = (1 bsl (LongSz*8)) - 1,
LongMax = UlongMax bsr 1,
LongMin = -(LongMax+1),
Uint64Max = (1 bsl 64) - 1,
Int64Max = Uint64Max bsr 1,
Int64Min = -(Int64Max+1),
Limits = [{IntMin,IntMax},{0,UintMax},{LongMin,LongMax},{0,UlongMax},{Int64Min,Int64Max},{0,Uint64Max}],
io:format("Limits = ~p\n", [Limits]),
lists:foreach(fun(I) ->
R1 = echo_int(I),
%%io:format("echo_int(~p) -> ~p\n", [I, R1]),
R2 = my_echo_int(I, Limits),
?line R1 = R2,
?line true = (R1 =:= R2),
?line true = (R1 == R2)
end, int_list()),

?line verify_tmpmem(TmpMem),
ok.

int_list() ->
Start = 1 bsl 200,
int_list([Start], -Start).
int_list([N | _]=List, End) when N<End ->
List;
int_list([N | _]=List, End) ->
int_list([N - (1 + (abs(N) div 3)) | List], End).

my_echo_int(I, Limits) ->
lists:map(fun({Min,Max}) ->
if I < Min -> false;
I > Max -> false;
true -> I
end
end, Limits).

clone(X) ->
binary_to_term(term_to_binary(X)).

Expand Down Expand Up @@ -1269,6 +1307,8 @@ send_blob_thread(_,_,_) -> ?nif_stub.
join_send_thread(_) -> ?nif_stub.
copy_blob(_) -> ?nif_stub.
send_term(_,_) -> ?nif_stub.
echo_int(_) -> ?nif_stub.
type_sizes() -> ?nif_stub.

nif_stub_error(Line) ->
exit({nif_not_loaded,module,?MODULE,line,Line}).
46 changes: 44 additions & 2 deletions erts/emulator/test/nif_SUITE_data/nif_SUITE.c
Expand Up @@ -28,6 +28,7 @@
static int static_cntA; /* zero by default */
static int static_cntB = NIF_SUITE_LIB_VER * 100;

static ERL_NIF_TERM atom_false;
static ERL_NIF_TERM atom_self;
static ERL_NIF_TERM atom_ok;
static ERL_NIF_TERM atom_join;
Expand Down Expand Up @@ -103,7 +104,7 @@ static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
msgenv_resource_type = enif_open_resource_type(env,NULL,"nif_SUITE.msgenv",
msgenv_dtor,
ERL_NIF_RT_CREATE, NULL);

atom_false = enif_make_atom(env,"false");
atom_self = enif_make_atom(env,"self");
atom_ok = enif_make_atom(env,"ok");
atom_join = enif_make_atom(env,"join");
Expand Down Expand Up @@ -481,6 +482,45 @@ static ERL_NIF_TERM type_test(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[
return enif_make_atom(env,"error");
}

static ERL_NIF_TERM echo_int(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
int sint;
unsigned uint;
long slong;
unsigned long ulong;
ErlNifSInt64 sint64;
ErlNifUInt64 uint64;
ERL_NIF_TERM sint_term = atom_false, uint_term = atom_false;
ERL_NIF_TERM slong_term = atom_false, ulong_term = atom_false;
ERL_NIF_TERM sint64_term = atom_false, uint64_term = atom_false;

if (enif_get_int(env, argv[0], &sint)) {
sint_term = enif_make_int(env, sint);
}
if (enif_get_uint(env, argv[0], &uint)) {
uint_term = enif_make_uint(env, uint);
}
if (enif_get_long(env, argv[0], &slong)) {
slong_term = enif_make_long(env, slong);
}
if (enif_get_ulong(env, argv[0], &ulong)) {
ulong_term = enif_make_ulong(env, ulong);
}
if (enif_get_int64(env, argv[0], &sint64)) {
sint64_term = enif_make_int64(env, sint64);
}
if (enif_get_uint64(env, argv[0], &uint64)) {
uint64_term = enif_make_uint64(env, uint64);
}
return enif_make_list6(env, sint_term, uint_term, slong_term, ulong_term, sint64_term, uint64_term);
}

static ERL_NIF_TERM type_sizes(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
return enif_make_tuple2(env, enif_make_int(env, sizeof(int)),
enif_make_int(env, sizeof(long)));
}

static ERL_NIF_TERM tuple_2_list(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
int arity = -1;
Expand Down Expand Up @@ -1417,7 +1457,9 @@ static ErlNifFunc nif_funcs[] =
{"send_blob_thread", 3, send_blob_thread},
{"join_send_thread", 1, join_send_thread},
{"copy_blob", 1, copy_blob},
{"send_term", 2, send_term}
{"send_term", 2, send_term},
{"echo_int", 1, echo_int},
{"type_sizes", 0, type_sizes}
};

ERL_NIF_INIT(nif_SUITE,nif_funcs,load,reload,upgrade,unload)
Expand Down

0 comments on commit 1c09660

Please sign in to comment.