簡體   English   中英

調用enif_free()時出現分段錯誤

[英]Segmentation fault when calling enif_free()

我有一些代碼應該使用Erlang管理O(1)訪問和讀取時間的3維數組。 因此,我正在使用Erlang NIF。 除了release()函數,其他所有東西都工作正常。 調用它時總是會遇到細分錯誤,我也不知道為什么。

這是我的代碼:

#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);

這是我的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.".

順便說一句,這是我的測試代碼:

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

編輯:好吧,它變得越來越怪異...經過一些測試,我弄清楚了我得到** exception error: [] if enif_free(data->array); 是該函數的最后一次調用。 即使在enif_free(data->array);之后僅存在一個println(),在其他位置我仍然會遇到分段錯誤enif_free(data->array); 經過一些調試后,我還發現enif_free(data->array);之前的每一行enif_free(data->array); 被稱為。 因此,異常似乎發生在enif_free(data->array) 有人知道這意味着什么嗎?

EDIT2:只需離開enif_free(data->array); 出去也無濟於事。 我也遇到了細分錯誤。

通過解決幾個問題,我能夠使您的代碼正確運行。

首先,您的代碼假定可以通過將ERL_NIF_TERMNULL比較來檢查ERL_NIF_TERM的有效性,這是不正確的。 您可以通過以下方法解決此問題:將所有數組元素初始化為0(通過調用enif_make_int(env, 0)設置每個元素),或使用結構數組,其中每個結構均持有ERL_NIF_TERM和一個unsigned char標志以指示是否該術語是否有效。 如果選擇后一種方式,你可以簡單地memset結構體值設置為0,如果主叫方請求通過一個未初始化的元素mutArray:get/4 ,只返回enif_make_badarg(env)來表示他們通過壞的參數調用。

其次,當set_nifrelease函數需要返回ERL_NIF_TERM時,它們都聲明為返回void 為了解決這個問題,你可以糾正他們的返回類型,然后再返回argv[4]set_nifenif_make_int(env, 0)release

最后,您的enif_open_resource_type調用的第二個參數需要為NULL而不是您要傳遞的"mutArray"值,如erl_nif手冊頁所示。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM