[erlang-questions] enif_free_env crashes VM
Volodymyr Kyrychenko
vladimir.kirichenko@REDACTED
Mon Nov 11 17:08:33 CET 2013
Heya,
I have big data structure and need to have massively parallel access to
it. SO i invented the wheel called references. Here is how it supposed
to work - it is NIF copying this BDS into process independent
environment and giving processes reference to the term in that env.
Sometimes structure gets updated and reference supposed to be destroyed
in NIF destructor. Everything was fine until things got real with
massive access. VM just gets silently crushed w/o crash_dump. It was
discovered that enif_free_env do not crashes vm itself but calling it
crashes VM elsewhere - probably someone tries to read dereferenced
value. Am I missing something or its a bug? R15B3 Linux.
Here is the code:
== xl_ref.c =========================================================
#include <erl_nif.h>
#include <stdio.h>
ERL_NIF_TERM xl_ref_new(ErlNifEnv* env, int argc, const ERL_NIF_TERM
argv[]);
ERL_NIF_TERM xl_ref_value(ErlNifEnv* env, int argc, const ERL_NIF_TERM
argv[]);
void xl_ref_dtor(ErlNifEnv* env, void* arg);
int on_load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info);
static ErlNifFunc nif_funcs[] = {
{"new", 1, xl_ref_new},
{"value", 1, xl_ref_value}
};
ERL_NIF_INIT(xl_ref, nif_funcs, &on_load, NULL, NULL, NULL)
typedef struct { ErlNifEnv* env; ERL_NIF_TERM value; } ref_t;
static ErlNifResourceType* XL_REF_RESOURCE;
ERL_NIF_TERM xl_ref_new(ErlNifEnv* env, int argc, const ERL_NIF_TERM
argv[]) {
ERL_NIF_TERM object = argv[0];
ref_t* ref = (ref_t*)enif_alloc_resource(XL_REF_RESOURCE,
sizeof(ref_t));
ref->env = enif_alloc_env();
ref->value = enif_make_copy(ref->env, object);
ERL_NIF_TERM ref_term = enif_make_resource(env, ref);
enif_release_resource(ref);
return ref_term;
}
ERL_NIF_TERM xl_ref_value(ErlNifEnv* env, int argc, const ERL_NIF_TERM
argv[]) {
ref_t* ref;
if (enif_get_resource(env, argv[0], XL_REF_RESOURCE, (void**)&ref))
return ref->value;
else
return enif_make_badarg(env);
}
void xl_ref_dtor(ErlNifEnv* env, void* arg) {
ref_t* ref = (ref_t*) arg;
//Here is the problem
enif_free_env(ref->env);
}
int on_load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) {
ErlNifResourceFlags flags = (ErlNifResourceFlags)(ERL_NIF_RT_CREATE
| ERL_NIF_RT_TAKEOVER);
XL_REF_RESOURCE = enif_open_resource_type(env, NULL,
"xl_ref_resource", &xl_ref_dtor, flags, 0);
return 0;
}
== xl_ref.erl ==============================================
-module(xl_ref).
-author("volodymyr.kyrychenko@REDACTED").
-on_load(init/0).
%% API
-export([new/1, value/1]).
-export_type([ref/0]).
-opaque(ref() :: reference()).
init() -> erlang:load_nif(find_nif(xl_stdlib, ?MODULE), 0).
-spec(new(term()) -> ref()).
new(_X) -> erlang:nif_error(nif_not_loaded).
-spec(value(ref()) -> term()).
value(_R) -> erlang:nif_error(nif_not_loaded).
find_nif(App, Module) ->
filename:join(priv_dir(App, Module), atom_to_list(Module)).
priv_dir(App, Module) ->
case code:priv_dir(App) of
{error, _} ->
EbinDir = filename:dirname(code:which(Module)),
AppPath = filename:dirname(EbinDir),
filename:join(AppPath, "priv");
Path -> Path
end.
=== xl_ref_tests.erl =========================================
-module(xl_ref_tests).
-author("Volodymyr Kyrychenko <vladimir.kirichenko@REDACTED>").
-include_lib("eunit/include/eunit.hrl").
ref_test() ->
ets:new(test, [named_table, public]),
ets:insert(test, {status, false}),
tree_refresh(1),
spawn_link(fun() -> tree_refresh(20) end),
access(self(), 100000),
receive
ok -> ok
end,
io:format(user, "done~n", []),
ets:delete(t).
access(Pid, 0) -> Pid ! ok;
access(Pid, X) ->
spawn_link(fun() ->
[{t, Ref}] = ets:lookup(test, t),
io:format(user, "~p\taccess start~n", [self()]),
gb_trees:values(xl_ref:value(Ref)),
io:format(user, "~p\taccess done~n", [self()])
end),
access(Pid, X - 1).
tree_refresh(0) -> ok;
tree_refresh(X) ->
T = lists:foldl(fun(I, Tree) ->
gb_trees:insert(I, I, Tree)
end, gb_trees:empty(), lists:seq(1, 10000)),
Ref = xl_ref:new(T),
ets:insert(test, {t, Ref}),
timer:sleep(100),
tree_refresh(X - 1).
=================================================================
--
Volodymyr Kyrychenko
More information about the erlang-questions
mailing list