# Segfault using ccall on initialization function

**URL:** https://discourse.julialang.org/t/segfault-using-ccall-on-initialization-function/40212
**Category:** General Usage
**Created:** [May 26, 2020, 6:27pm UTC](https://discourse.julialang.org/t/segfault-using-ccall-on-initialization-function/40212 "2020-05-26T18:27:27Z")
**Posts on this page:** 1
**Showing post:** 11

<div class="post-metadata">

### Author: ![yuyichao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yuyichao/32/20_2.png) [@yuyichao](https://discourse.julialang.org/u/yuyichao)
#### Post date: [May 27, 2020, 3:15am UTC](https://discourse.julialang.org/t/segfault-using-ccall-on-initialization-function/40212/11 "2020-05-27T03:15:46Z")

</div>

> [@Matt\_Davis](#):
>
> Thanks very much for all the help. Do you mean it should look like this? I’ve also created a wrapper struct `TTensor` to maintain a reference to the data in `tblis_tensor`

> [@Matt\_Davis](#):
>
> ```julia
> _M = TTensor{T}(M,D,lens,strides)
> 
> ```

`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

```julia
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).

```julia
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,

> [@Matt\_Davis](#):
>
> ```julia
> 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
> 
> ```

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

> [@Matt\_Davis](#):
>
> ```julia
> _M = TTensor{T}(M,D,lens,strides)
> 
> ```

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.

* * *

> [@Matt\_Davis](#):
>
> With that construction, I am able to create and modify these structs, thank you. However, I am now receiving a segfault when trying to do basic addition operations with them.

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.

> [@Matt\_Davis](#):
>
> `Ptr{tblis_tensor{T2}}`

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.

```julia
    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,

> [@Matt\_Davis](#):
>
> ```julia
> A.tensor,idx_A,
> 
> ```

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.

---

_[View the full topic](https://discourse.julialang.org/t/segfault-using-ccall-on-initialization-function/40212)._
