Segfault using ccall on initialization function

M will not get modified by the ccall. If there’s any mutation that you want to capture, you have access to something that’s NOT a immutable object. With minimum change to this version of the code, you can do

rM = Ref(M)
ccall(..., (...,), rM, n, ...)
_M = TTensor{T}(rM[], ...)

Note that as I said, the Ref does NOT change what the ccall does and M won’t be mutated in either case. However, Ref(M) is mutated in both cases and you need to access it after the ccall to see the update value. (Again, this is only needed if the struct is actually being written to by the C code).

It can be simplified though. You don’t really need the Ref since you already have a perfectly fine mutable structore declared to hold the C structure, i.e. TTensor, all what you need is to pass the pointer within TTensor to C. The pointer is compatible in this case so you just need to pass the TTensor to C. This won’t make too much difference here but the same pattern should be used to avoid doing any copying when you use this later. By passing the TTensor to C directly, you can also use the builtin mechanism to keep the TTensor, and therefore all its fields, alive and you don’t need to define you own anymore. In all, it can be simplified to (untested).

function TTensor{T}(D) where T <: AbstractFloat
    strides = [1]
    lens = collect(size(D))
    for (i,v) in enumerate(lens[1:end-1])
        push!(strides,v*strides[i])
    end
    n::UInt32 = length(size(D))
    M = TTensor{T}(tblis_tensor{T}(zero(Int32),zero(Int32),
                                   0.0 + 0.0im,
                                   pointer(D),
                                   n,
                                   pointer(lens),
                                   pointer(strides)), D, lens, strides)
    if T == Float32
        tblis_init_tensor = dlsym(tblis,:tblis_init_tensor_s)
    elseif T == Float64
        tblis_init_tensor = dlsym(tblis,:tblis_init_tensor_d)
    else
        error("Type $T is not supported by TBLIS :(")
    end
    ccall(tblis_init_tensor, Cvoid, (Ref{TTensor{T}},Cuint,Ptr{Int},Ptr{T}, Ptr{Int}),
          M, n, lens, D, strides)
    return M
end

Note that there’s no GC.@preserve needed because the only place that uses the return values of the pointer is in the ccall. If you access the memory pointed to by, say, M.tensor._data anywhere in this function (including before the ccall), it must be enclosed in GC.@preserve M (or just for the corresponding array of course).


A few other notes,

Unless there’s good reason you have to use dlsym, you should just do a branch and have two different ccalls. If you have to use dlsym, you should cache the pointer. See PyCall for example of that.

This is gone in the new version but you can just write return TTensor{T}(M,D,lens,strides) (or even omit the return if that’s your style). Returning from a GC.@preserve block is totally safe.


I don’t think you are actually modifying them (the type, conj, attr and ndim fields for example) so that could be part of it.

I don’t think this will work, in that it should throw an error before you make the ccall. A Ref{tblis_tensor{T2}} should surpress the error but isn’t the right thing to do either. As I said, you want to pass a pointer to the C struct from your TTensor. A.tensor will not do that. The returned immutuable object from A.tensor has absolutely nothing to do with the memory of A from that point on. You need a pointer to the field and again, in this case it’s simply the pointer to the TTensor itself so you just need.

    ccall(tblis_tadd,Cvoid,(Ptr{Nothing},Ptr{Nothing},
                            Ref{TTensor{T2}},Cstring,
                            Ref{TTensor{T2}},Cstring),
          C_NULL,C_NULL,
          A,idx_A,
          B,idx_B)

Also note that,

does not keep either A, or the array stored in its field alive. If you are going this route (A is a const pointer so I assume the C code isn’t mutatint it and passing in a “copy” could be fine) you must manually perserve the A during the ccall or whatever period you are using those pointers.

2 Likes