I’m trying to interface with a C API for solving linear systems but I keep running into segfault errors. The algorithm uses a somewhat complex C structure, called LUSOLrec, to keep track of all the relevant data.
_LUSOLrec in C
typedef struct _LUSOLrec {
/* Parameter storage arrays */
int luparm[LUSOL_IP_LASTITEM + 1];
REAL parmlu[LUSOL_RP_LASTITEM + 1];
/* Arrays of length lena+1 */
int lena, nelem;
int *indc, *indr;
REAL *a;
/* Arrays of length m+1 (row storage) */
int maxm, m;
int *lenr, *ip, *iqloc, *ipinv, *locr;
/* Arrays of length n+1 (column storage) */
int maxn, n;
int *lenc, *iq, *iploc, *iqinv, *locc;
REAL *w, *vLU6L;
/* Extra arrays of length n for TCP and keepLU == FALSE */
REAL *Ha, *diagU;
int *Hj, *Hk;
/* Extra arrays of length m for TRP*/
REAL *amaxr;
/* Extra array for L0 stored by row for faster btran */
LUSOLmat *L0;
/* Miscellaneous data */
int expanded_a;
int replaced_c;
int replaced_r;
} LUSOLrec;
/* Sparse matrix data */
typedef struct _LUSOLmat {
REAL *a;
int *lenx, *indr, *indc, *indx;
} LUSOLmat;
I converted this to a Julia struct so I could access the fields both in Julia and in C.
LUSOLrec in Julia
struct LUSOLrec
luparm::NTuple{33,Cint}
parmlu::NTuple{21,Cdouble}
# Arrays of length lena+1
lena::Cint
nelm::Cint
indc::Array{Cint,1}
indr::Array{Cint,1}
a::Array{Cdouble,1}
# Arrays of length m+1 (row storage)
maxm::Cint
m::Cint
lenr::Array{Cint,1}
ip::Array{Cint,1}
iqloc::Array{Cint,1}
ipinv::Array{Cint,1}
locr::Array{Cint,1}
# Arrays of length n+1 (column storage)
maxn::Cint
n::Cint
lenc::Array{Cint,1}
iq::Array{Cint,1}
iploc::Array{Cint,1}
iqinv::Array{Cint,1}
locc::Array{Cint,1}
w::Array{Cdouble,1}
vLU6L::Array{Cdouble}
# Extra arrays of length n for TCP and keepLU == False
Ha::Array{Cdouble,1}
diagU::Array{Cdouble,1}
Hj::Array{Cint,1}
Hk::Array{Cint,1}
# Extra arrays of length m for TRP
amaxr::Array{Cdouble,1}
# Extra array for L0 stored by row for faster btran
L0::Ptr{LUSOLmat}
# Miscellaneous data
expanded_a::Cint
replaced_c::Cint
replaced_r::Cint
end
struct LUSOLmat
a::Array{Cdouble,1}
lenx::Array{Cint,1}
indr::Array{Cint,1}
indc::Array{Cint,1}
indx::Array{Cint,1}
end
The API includes this function for assigning some of the fields of the LUSOLrec struct
LUSOL_assign function
MYBOOL LUSOL_assign(LUSOLrec *LUSOL, int iA[], int jA[], REAL Aij[], int nzcount, MYBOOL istriplet)
{
int k, m, n, ij, kol;
m = 0;
n = 0;
kol = 1;
for(k = 0; k < nzcount; k++) {
/* First the row indicator */
ij = iA[k];
LUSOL->indc[k] = ij;
/* Then the column indicator;
Handle both triplet and column count formats */
if(istriplet)
ij = jA[k];
else {
if(k >= jA[kol])
kol++;
ij = kol;
}
LUSOL->indr[k] = ij;
/* Lastly the matrix value itself */
LUSOL->a[k] = Aij[k];
}
LUSOL->m = m;
LUSOL->n = n;
LUSOL->nelem = nzcount;
return( TRUE );
But when I try to call the above function in Julia I get a segfault. I’ve stepped through the function with gdb and it looks like everything is working as it should from within the function.
The code I’m using to run the function is
function lusol_assign(LUSOL::LUSOLrec, iA::Array{Cint,1}
,jA::Array{Cint,1},Aij::Array{Cdouble,1},
nzcount::Integer,istriplet::Integer)
output = ccall(plusol_assign,
Cuchar,
(Ref{LUSOLrec},Ptr{Cint},Ptr{Cint},Ptr{Cdouble},
Cint,Cuchar),
LUSOL, iA, jA, Aij, nzcount, istriplet)
return output
end
using SparseArrays
LUSOL = lusol_rec(5,5,1000)
A = sprand(5,5,.5)
(i,j,v) = findnz(A)
i = convert(Array{Cint,1},i)
j = convert(Array{Cint,1},j)
lusol_assign(LUSOL,i,j,v,length(i),1)
Where lusol_rec constructs the initial LUSOL object.
lusol_rec function
function lusol_rec(m,n,lena)
luparm = tuple(zeros(Cint,33)...)
parmlu = tuple(zeros(Cdouble, 21)...)
# Arrays of length lena + 1
lena = Cint(lena)
nelm = 0
indc = zeros(Cint,lena+1)
indr = zeros(Cint,lena+1)
a = zeros(Cdouble,lena+1)
# Arrays of length m+1
maxm = m
lenr = zeros(Cint,m+1)
ip = zeros(Cint,m+1)
iqloc = zeros(Cint,m+1)
ipinv = zeros(Cint,m+1)
locr = zeros(Cint,m+1)
#Arrays of length n+1
maxn = n
lenc = zeros(Cint,n+1)
iq = zeros(Cint,n+1)
iploc = zeros(Cint,n+1)
iqinv = zeros(Cint,n+1)
locc = zeros(Cint,n+1)
w = zeros(Cdouble, n+1)
vLU6L = zeros(Cdouble, n+1)
#Extra arrays of length n for TCP and keepLU = False
Ha = zeros(Cdouble,n)
diagU = zeros(Cdouble, n)
Hj = zeros(Cint, n)
Hk = zeros(Cint, n)
# Extra arrays of length m for TRP
amaxr = zeros(Cdouble, m)
# Extra array for L) stored for faster btrain
L0 = Ptr{LUSOLmat}(C_NULL)
# Miscellaneous data
expanded_a = Cint(0)
expanded_c = Cint(0)
replaced_r = Cint(0)
return LUSOLrec(luparm,parmlu,lena,nelm,indc,indr,a,maxm,
m,lenr,ip,iqloc,ipinv,locr,maxn,n,lenc,
iq,iploc,iqinv,locc,w,vLU6L,Ha,diagU,Hj,
Hk,amaxr,L0,expanded_a,expanded_c,
replaced_r)
end
Does anyone have any idea why this code is causing a segfault? I’m pretty sure I converted the LUSOLrec structure to a Julia structure correctly and called the LUSOL_assign function correctly as well. I can even see that it looks like it’s working fine using gdb to step through the LUSOL_assign function. But at the very end when it completes the function I get a segfault anyways. What am I doing wrong?