c - Segmentation fault when calling enif_free() -
i have code should manage 3 dimensional array o(1) access , reading time in erlang. therefor i'm using erlang nifs. working fine except release() function. segmentation fault when calling , have no idea why.
here code:
#include "erl_nif.h" static erlnifresourcetype *data_resource; typedef struct { int size; erl_nif_term *** array; erl_nif_term defaultvalue; } data; static erl_nif_term new3dimarray(erlnifenv* env, int argc, const erl_nif_term argv[]) { data *data = (data *)enif_alloc_resource(data_resource, sizeof(data)); int size; enif_get_int(env, argv[0], &size); if(argc > 1) { data->defaultvalue = argv[1]; }else{ data->defaultvalue = null; } data->size = size; data->array = (erl_nif_term ***)enif_alloc(sizeof(erl_nif_term **) * size); int x = 0; while(x < size) { data->array[x] = (erl_nif_term **)enif_alloc(sizeof(erl_nif_term *) * size); int y = 0; while(y < size) { data->array[x][y] = (erl_nif_term *)enif_alloc(sizeof(erl_nif_term) * size); y++; } x++; } return enif_make_resource(env, data); } static erl_nif_term get_nif(erlnifenv* env, int argc, const erl_nif_term argv[]) { data *data; enif_get_resource(env, argv[0], data_resource, &data); int x; int y; int z; enif_get_int(env, argv[1], &x); enif_get_int(env, argv[2], &y); enif_get_int(env, argv[3], &z); erl_nif_term res = data->array[x][y][z]; if(res == null && data->defaultvalue != null) { res = data->defaultvalue; } return res; } static void set_nif(erlnifenv* env, int argc, const erl_nif_term argv[]) { data *data; enif_get_resource(env, argv[0], data_resource, &data); int x; int y; int z; enif_get_int(env, argv[1], &x); enif_get_int(env, argv[2], &y); enif_get_int(env, argv[3], &z); erl_nif_term value = argv[4]; data->array[x][y][z] = value; } static void release(erlnifenv* env, int argc, const erl_nif_term argv[]) { data *data; enif_get_resource(env, argv[0], data_resource, &data); int x = 0; while(x < data->size) { int y = 0; while(y < data->size) { enif_free(data->array[x][y]); y++; } enif_free(data->array[x]); x++; } enif_free(data->array); enif_release_resource(data); } static void cleanup(erlnifenv *env, void *obj){} static int load(erlnifenv *env, void **priv_data, erl_nif_term load_info){ data_resource = enif_open_resource_type(env, "mutarray", "data_resource", &cleanup, erl_nif_rt_create, 0); return 0; } static erlniffunc nif_funcs[] = { {"new_3_dim_array", 1, new3dimarray}, {"new_3_dim_array", 2, new3dimarray}, {"get", 4, get_nif}, {"set", 5, set_nif}, {"release", 1, release} }; erl_nif_init(mutarray, nif_funcs, load, null, null, null); this erlang code (to make arity clearer):
module(mutarray). %% ==================================================================== %% api functions %% ==================================================================== -export([init/0, new_3_dim_array/1, new_3_dim_array/2, get/4, set/5, release/1]). init() -> erlang:load_nif("./mutarray", 0). new_3_dim_array(_size) -> "nif not loaded yet.". new_3_dim_array(_size, _defaultvalue) -> "nif not loaded yet.". get(_array, _x, _y, _z) -> "nif not loaded yet.". set(_array, _x, _y, _z, _value) -> "nif not loaded yet.". release(_array) -> "nif not loaded yet.". btw, testcode:
mutarray:init(), = mutarray:new_3_dim_array(100), mutarray:release(a). edit: ok gets more , more weird... after testing fidured out ** exception error: [] if enif_free(data->array); last call of function. @ every other position still segmentation fault, if there println() after enif_free(data->array);. after debugging figured out every line before enif_free(data->array); called. exception seems happen @ enif_free(data->array). know means?
edit2: leaving enif_free(data->array); out doesn't either. segmentation fault well.
i able code running correctly fixing several problems.
first, code assumes it's ok check validity of erl_nif_term comparing null, incorrect. can fix either initializing of array elements 0 (by calling enif_make_int(env, 0) set each element), or using array of structs each struct holds erl_nif_term , unsigned char flag indicate whether term valid or not. if choose latter approach, memset struct values 0, , if caller requests uninitialized element via mutarray:get/4, return enif_make_badarg(env) indicate passed bad arguments call.
second, both set_nif , release functions declared return void when need return erl_nif_term instead. fix can correct return types, , return argv[4] set_nif , enif_make_int(env, 0) release.
lastly, second argument enif_open_resource_type call needs null rather "mutarray" value you're passing, the erl_nif man page indicates.
Comments
Post a Comment