简体   繁体   English

调用enif_free()时出现分段错误

[英]Segmentation fault when calling enif_free()

I have some code that should manage a 3 dimensional array with O(1) access and reading time in Erlang. 我有一些代码应该使用Erlang管理O(1)访问和读取时间的3维数组。 Therefor I'm using Erlang NIFs. 因此,我正在使用Erlang NIF。 Everything is working fine except for the release() function. 除了release()函数,其他所有东西都工作正常。 I always get a segmentation fault when calling it and I have no idea why. 调用它时总是会遇到细分错误,我也不知道为什么。

Here is my 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 is my Erlang code (to make the arity clearer): 这是我的Erlang代码(以使Arity更清晰):

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, this is my Testcode: 顺便说一句,这是我的测试代码:

mutArray:init(),
A = mutArray:new_3_dim_array(100),
mutArray:release(A).

EDIT: Ok it gets more and more weird... After some testing I fidured out that I get ** exception error: [] if enif_free(data->array); 编辑:好吧,它变得越来越怪异...经过一些测试,我弄清楚了我得到** exception error: [] if enif_free(data->array); is the last call of the function. 是该函数的最后一次调用。 At every other position I still get the segmentation fault, even if there is just a println() after enif_free(data->array); 即使在enif_free(data->array);之后仅存在一个println(),在其他位置我仍然会遇到分段错误enif_free(data->array); . After some debugging I also figured out that every line before enif_free(data->array); 经过一些调试后,我还发现enif_free(data->array);之前的每一行enif_free(data->array); was called. 被称为。 So the exception seems to happen at enif_free(data->array) . 因此,异常似乎发生在enif_free(data->array) Does anybody know what this means? 有人知道这意味着什么吗?

EDIT2: Simply leaving enif_free(data->array); EDIT2:只需离开enif_free(data->array); out doesn't help either. 出去也无济于事。 I get a segmentation fault then as well. 我也遇到了细分错误。

I was able to get your code running correctly by fixing several problems. 通过解决几个问题,我能够使您的代码正确运行。

First, your code assumes that it's OK to check the validity of an ERL_NIF_TERM by comparing it to NULL , which is incorrect. 首先,您的代码假定可以通过将ERL_NIF_TERMNULL比较来检查ERL_NIF_TERM的有效性,这是不正确的。 You can fix this by either initializing all of your array elements to 0 (by calling enif_make_int(env, 0) to set each element), or by using an array of structs where each struct holds an ERL_NIF_TERM and an unsigned char flag to indicate whether the term is valid or not. 您可以通过以下方法解决此问题:将所有数组元素初始化为0(通过调用enif_make_int(env, 0)设置每个元素),或使用结构数组,其中每个结构均持有ERL_NIF_TERM和一个unsigned char标志以指示是否该术语是否有效。 If you choose the latter approach, you could simply memset the struct values to 0, and if a caller requests an uninitialized element via mutArray:get/4 , just return enif_make_badarg(env) to indicate they passed bad arguments to the call. 如果选择后一种方式,你可以简单地memset结构体值设置为0,如果主叫方请求通过一个未初始化的元素mutArray:get/4 ,只返回enif_make_badarg(env)来表示他们通过坏的参数调用。

Second, both your set_nif and release functions are declared to return void when they need to return ERL_NIF_TERM instead. 其次,当set_nifrelease函数需要返回ERL_NIF_TERM时,它们都声明为返回void To fix this you can correct their return types, and then return argv[4] from set_nif and enif_make_int(env, 0) from release . 为了解决这个问题,你可以纠正他们的返回类型,然后再返回argv[4]set_nifenif_make_int(env, 0)release

Lastly, the second argument to your enif_open_resource_type call needs to be NULL rather than the "mutArray" value you're passing, as the erl_nif man page indicates. 最后,您的enif_open_resource_type调用的第二个参数需要为NULL而不是您要传递的"mutArray"值,如erl_nif手册页所示。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM