Proper resource handling in Elixir NIF - c

I am trying to implent a NIF for simple linear algebra. Here is my internal structure for matrix:
typedef struct la_matrix {
uint rows, columns;
double **data;
} la_matrix;
And here is a "constructor" for it:
la_result
la_matrix_constructor(la_matrix **res,
const uint rows,
const uint columns)
{
if (rows == 0 || columns == 0)
return dimensional_problems;
// allocate memory for meta-structure
*res = malloc(sizeof(la_matrix));
if (*res == NULL)
return null_ptr;
// allocater memory for array of pointers to rows
(*res)->data = malloc(rows * sizeof(double*));
if ((*res)->data == NULL) {
free(*res);
return null_ptr;
}
//allocate memory for each row
uint i = 0;
bool failed = false;
for (; i < rows; i++) {
(*res)->data[i] = malloc(columns * sizeof(double));
if ((*res)->data[i] == NULL) {
failed = true;
break;
}
}
if (failed) {
// one step back, since i-th row wasn't allocated
i -= 1;
for(; i < ~((uint) 0); i--)
free((*res)->data[i]);
free((*res)->data);
free(*res);
return null_ptr;
}
(*res)->rows = rows;
(*res)->columns = columns;
return ok;
}
Then I have two wrappers for NIF -- one for constructor:
static ERL_NIF_TERM
nif_matrix_constructor(ErlNifEnv *env,
int argc,
const ERL_NIF_TERM *argv)
{
uint rows, columns;
enif_get_uint(env, argv[0], &rows);
enif_get_uint(env, argv[1], &columns);
la_matrix **mat_res = enif_alloc_resource(LA_MATRIX_TYPE, sizeof(la_matrix *));
la_matrix *mat_ptr;
la_result result = la_matrix_constructor(&mat_ptr, rows, columns);
if (result != ok)
return enif_make_atom(env, "err");
memcpy((void *) mat_res, (void *) &mat_ptr, sizeof(la_matrix *));
ERL_NIF_TERM term = enif_make_resource(env, mat_res);
enif_release_resource(mat_res);
return term;
}
And one to test if the constructor works correctly:
static ERL_NIF_TERM
nif_matrix_rows(ErlNifEnv *env,
int argc,
const ERL_NIF_TERM *argv)
{
la_matrix *mat_ptr;
if(!enif_get_resource(env, argv[0], LA_MATRIX_TYPE, (void **) &mat_ptr))
return enif_make_atom(env, "err");
return enif_make_uint(env, mat_ptr->rows);
}
It seems that the constructor wrapper works perfectly fine (I've tested it with using printf), but nif_matrix_rows returns strange results, e.g.
iex(1)> mat = LinearAlgebra.matrix(2,3)
""
iex(2)> LinearAlgebra.rows(mat)
1677732752
And directly passing LinearAlgebra.matrix(2,3) to LinearAlgebra.rows twice results in segfault:
iex(3)> LinearAlgebra.rows(LinearAlgebra.matrix(2,3))
1543520864
iex(4)> LinearAlgebra.rows(LinearAlgebra.matrix(2,3))
zsh: (core dumped) iex -S mix
(Note different results for the "same" matrices).
I was following Andrea Leopardi's tutorial with minor (I don't really sure if they are so) changes to fight gcc warnings. Most important, IMHO, was this part
la_matrix *mat_ptr;
if(!enif_get_resource(env, argv[0], LA_MATRIX_TYPE, (void **) &mat_ptr))
return enif_make_atom(env, "err");
while Andrea Leopardi uses
db_conn_t **conn_res;
enif_get_resource(env, argv[0], DB_RES_TYPE, (void *) conn_res);
db_conn_t *conn = *conn_res;
But it looks invalid for me since, AFAIR, (void *) conn_res assumes that conn_res was initalized.
Here is an error which occurs when I use Andrea's way:
src/nif.c: In function ‘nif_matrix_rows’:
src/nif.c:72:3: warning: ‘mat_res’ is used uninitialized in this function [-Wuninitialized]
enif_get_resource(env, argv[0], LA_MATRIX_TYPE, (void *) mat_res);
And calling LinearAlgebra.rows from iex causes segfault.
Could one tell me a proper way for handling structures in NIFs?
P.S. Sorry for C code, I've never wrote something more than bunch of helloworlds.

The problem was indeed in nif_matrix_rows: with my code Elixir passes a pointer to a pointer to a structure (la_matrix **) and I assumed that it would be a proper pointer.
So, quick fix is
static ERL_NIF_TERM
nif_matrix_rows(ErlNifEnv *env,
int argc,
const ERL_NIF_TERM *argv)
{
la_matrix const **mat_res;
if(!enif_get_resource(env, argv[0], LA_MATRIX_TYPE,(void **) &mat_res))
return enif_make_atom(env, "err");
la_matrix const *mat_ptr = *mat_res;
return enif_make_uint(env, mat_ptr->rows);
}
However, I'll wait some time for more elegant solution and won't accept this answer so far.

Related

How to return a char** as a function argument

I have a function that returns a pointer to pointers of chars (char**). The function takes 2 arguments
int* num_paths: a pointer to an integer to indicate the number of strings to be returned.
int* errno: a pointer to an integer to indicate an error code. This can contain different values, so I cannot simply check if NULL is returned in case of error.
Some example code is written below (with the majority of error checks omitted for simplicity):
char** get_paths(int* num_paths, int* errno) {
char* path1 = NULL;
char* path2 = NULL;
char** paths = NULL;
if(errno == NULL) {
printf("Set errno in case of error, but cannot dereference NULL pointer\n");
goto exit;
}
path1 = calloc(1, strlen("foo") + 1);
path2 = calloc(1, strlen("bar") + 1);
strcpy(path1, "foo");
strcpy(path2, "bar");
*num_paths = 2;
paths = calloc(1, *num_paths*sizeof(char *));
paths[0] = path1;
paths[1] = path2;
*errno = 0;
exit:
return paths;
}
int main(void) {
char** paths = NULL;
int num_paths = 0;
int errno = 0;
paths = get_paths(&num_paths, &errno);
if(errno != 0) {
return -1;
}
for(int i = 0; i < num_paths; i++) {
printf("%s\n", paths[i]);
free(paths[i]);
}
free(paths);
}
The problem I have with this is that I can't set the error code in case a NULL pointer is passed as argument for errno. You could argue that this is a user error, but I would still like to avoid this situation in the first place.
So my question is: can I rewrite my get_paths function such that it returns an integer as error code, but also returns a char** through the function arguments without resorting to char*** like in the following example:
int get_paths_3(char*** paths, int* num_paths) {
char* path1 = NULL;
char* path2 = NULL;
path1 = calloc(1, strlen("foo") + 1);
path2 = calloc(1, strlen("bar") + 1);
strcpy(path1, "foo");
strcpy(path2, "bar");
*num_paths = 2;
*paths = calloc(1, *num_paths*sizeof(char *));
(*paths)[0] = path1;
(*paths)[1] = path2;
return 0;
}
This is pretty much the only case where "three star" pointers are fine to use. It's fairly common practice in API design to reserve the return value for error codes, so this situation isn't uncommon.
There are alternatives, but they are arguably not much better. You could abuse the fact that void* can be converted to/from char** but it isn't much prettier and less type safe:
// not recommended
int get_paths_4 (void** paths, size_t* num_paths)
{
char* path1 = calloc(1, strlen("foo") + 1);
char* path2 = calloc(1, strlen("bar") + 1);
strcpy(path1, "foo");
strcpy(path2, "bar");
*num_paths = 2;
char** path_array;
path_array= calloc(1, *num_paths*sizeof(char *));
path_array[0] = path1;
path_array[1] = path2;
*paths = path_array;
return 0;
}
...
void* vptr;
size_t n;
get_paths_4 (&vptr, &n);
char** paths = vptr;
for(size_t i=0; i<n; i++)
{
puts(paths[i]);
}
A more sound alternative might be wrap all your parameters into a single struct type and pass that one as a pointer.
Unfortunately you cannot mixing return types in C is a terrible mistake and should not be done, you can either:
return the pointer you need and add a error code to a variable
return the error code and add the pointer to a variable
Both are valid strategies and I'd pick the one that matches the rest of your code to have consistency.

Creating an 2D Array of char* an fill it with data from sqlite in callback function

In my function I call the rc = sqlite3_exec(db, sqlStatement, callback, &a, &zErrMsg); function with the callback function.
In this callback function I want to fill a 2D Array of char* with the data from the database.
struct mytable
{
char ***data;
size_t dim;
};
static int callback(void *data, int argc, char **argv, char **azColName)
{
struct mytable *old = (mytable *)data;
char ***temp;
old->dim++;
temp = (char ***)realloc(old->data, old->dim * sizeof(*old->data));
if (temp)
{
old->data = temp;
old->data[old->dim - 1] = NULL;
}
else
{
logging_logError("Kein virtueller RAM mehr vorhanden ... !", __FILE__);
return EXIT_FAILURE;
}
for (int i = 0; i < old->dim; i++)
{
char **temp2 = (char **)realloc(old->data[i], sizeof(argv) * sizeof(*old->data[i]));
if (temp2)
{
old->data[i] = temp2;
old->data[i][argc - 1] = NULL;
}
else
{
logging_logError("Kein virtueller RAM mehr vorhanden ... !", __FILE__);
return EXIT_FAILURE;
}
}
/*Here I try to store the data from each column
in the corresponding position in the 2D array of char* */
for (int i = 0; i < argc; i++)
{
char *s = argv[i];
temp[old->dim - 1][i] = s;
}
return 0;
}
When I print out the data I returned, I get some mysterious signs.
What I want to have is something like this (in array structure):
["1"]["Paul"]["street 1"]["some address"]
["2"]["Anna"]["street asdf"]["some address"]
["3"]["Martin"]["street bfg"]["some address"]
EDIT:
This was my previous question
I don't find it documented specifically, but it seems probable that the argv strings passed into your callback are good only until the callback returns. I don't see how SQLite could work otherwise -- the callback is not responsible for managing the memory for those strings, so SQLite must do so internally.
Therefore, instead of recording the original string pointers in your array, duplicate the strings, and store pointers to the duplicates. MSVC++ provides strdup(), so you might achieve that by replacing ...
char *s = argv[i];
... with ...
char *s = strdup(argv[i]);
. Do be aware that by doing so you assume responsibility for freeing those strings when you're done with them.

Memory access in pthreads

I am writing a unit test that involves running multiple threads and I ran into a memory access issue that I can't seem to understand.
Here is the original (pseudo) code:
void thread_func(void * err) {
/*foo will return an allocated error_type if error occurs else NULL*/
err = (void *) foo(...)
pthread_exit(NULL);
}
void unit_test() {
int i = 0;
err_type *err_array[10];
pthread_t threads[10];
for (i = 0; i < 10; i++) {
pthread_create(&(threads[i]), NULL, thread_func, (void *) err_array[i]);
}
for(i = 0; i < 10; i++) {
pthread_join(threads[i], NULL);
ASSERT_NULL(err_array[i]);
}
}
What I am confused about is that all the threads will return NULL (checked with a gdb), however err_array[1] and err_array[5] will be NOT NULL. And instead of a valid err_type, they will contain garbage. In the case of err_array[1] will contain a string of the unit_test file path, and err_array[5] will contain a bunch of access out of bounds addresses.
A work-around I've found is to use a global err_array, and pass in the index for each element to the thread. As well as initializing all the elements of the array to NULL.
My question is why does the above 2 methods work, and not the original code?
The err variable is local to thread_func. It goes out of scope when thread_func returns. You need to pass the thread a pointer to the thing you want it to modify, not the current value of the thing you want it to modify.
So:
void thread_func(void ** err) {
/*foo will return an allocated error_type if error occurs else NULL*/
*err = (void *) foo(...)
pthread_exit(NULL);
}
And:
pthread_create(&(threads[i]), NULL, thread_func, (void **) &err_array[i]);

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. Therefor I'm using Erlang NIFs. Everything is working fine except for the release() function. 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):
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); 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);. After some debugging I also figured out that every line before enif_free(data->array); was called. So the exception seems to happen at enif_free(data->array). Does anybody know what this means?
EDIT2: Simply leaving 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. 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. 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.
Second, both your set_nif and release functions are declared to return void when they need to return ERL_NIF_TERM instead. 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.
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.

qsort not working correctly because of null pointer

Code:
struct company_struct
{
company_name_t company_name;
double stock_price;
company_stock_t company_stock;
};
typedef struct company_struct company_struct_t;
int sort_by_price(const void * ptr1, const void * ptr2)
{
assert(ptr1 != NULL);
assert(ptr2 != NULL);
const company_struct_t * ptr1_price = (const company_struct_t *) ptr1;
const company_struct_t * ptr2_price = (const company_struct_t *) ptr2;
assert(ptr1_price->stock_price != NULL); //??? Why it failed?
assert(ptr2_price->stock_price != NULL);
if(ptr1_price->stock_price > ptr2_price->stock_price) return -1;
else if (ptr1_price->stock_price == ptr2_price->stock_price) return 0;
else if (ptr1_price->stock_price < ptr2_price->stock_price) return 1;
}
qsort(company_list, *size, sizeof(company_list), sort_by_price);
When I run my program, the assert failed. I am relatively new to C, please bear with me.
You need to pass the size of an individual element as the third parameter of qsort, like this:
qsort(company_list, *size, sizeof(company_struct_t), sort_by_price);
Also make sure that size points to an int that holds the number of items to be sorted.
If it really is this line that's failing,
assert(ptr1_price->stock_price != NULL); //??? Why it failed?
you should crank-up your compiler warnings. You should get a warning for comparing a double to a pointer. [And for prices, it's usually better to use an integer. What would $0.000003 mean?]

Resources