Julia - C types with struct hack cause segfault
c, julia, struct
Solution
As mentioned in the C interface section of the Julia manual, regarding inline type/struct members:
Arrays of unknown size are not supported.
However, it is possible to use the address of the struct to figure out the offset to the array data (just like in C), and then access that data using unsafe_wrap.
Here is a complete example:
test.c
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int x;
int y;
int z;
} contained;
typedef struct {
int n;
contained arr[];
} mystruct;
mystruct *return_mystruct() {
mystruct* ms = malloc(sizeof(mystruct) + 6*sizeof(contained));
ms->n = 6;
for (int i=0; i < 6; i++) {
printf("i: %d\n", i);
ms->arr[i].x = i+1;
ms->arr[i].y = i+1;
ms->arr[i].z = i+1;
};
return ms;
}
compile with: `gcc -shared -o test test.c`
julia:
immutable contained
x::Cint
y::Cint
z::Cint
end
immutable mystruct
n::Cint
end
ms = ccall((:return_mystruct, "test"), Ptr{mystruct}, ())
n = unsafe_load(ms).n
addr = reinterpret(Ptr{contained}, ms+sizeof(mystruct))
arr = unsafe_wrap(Vector{contained}, addr, n)
Notes:
- `type` -> `immutable` in order to ensure that the layout is C compatible (see manual)
- note that the address must be valid for the lifetime of any Julia reference to the memory, which generally means it must be heap-allocated)
Problem
This question is a followup to Julia - C interface with nonfundamental types, with enough new information to be considered a different question. I use a C library that has two types like this, with three possible versions of `mystruct`: ``` struct contained { int x; int y; int z; }; struct mystruct { int n; //original: // contained* arr; //struct hack version 1: // contained arr[1]; //struct hack version 2: contained arr[]; }; ``` Using the answer from the original question, I have defined the following corresponding Julia types, which work fine with the original version of `mystruct`, but not either version using the struct hack: ``` type contained x::Cint y::Cint z::Cint end type mystruct n::Cint arr::Ptr{contained} end ``` If I call a C function from Julia which returns a `Ptr{mystruct}` and save it as `ms`, I can put `m = unsafe_load(ms)` and see `m.n` and the pointer `m.arr`, but I can only check its values with `unsafe_load(m.arr)` in the original case. Otherwise `unsafe_load(m.arr)` causes a segfault. What is the right way in Julia to handle C structs containing variable length arrays defined in this fashion? I would use only the original definition of `mystruct` with `contained *arr` since it works as expected, but I need code that works for the other cases too.