# Finalizer only works with mutable structs?

**URL:** <https://discourse.julialang.org/t/finalizer-only-works-with-mutable-structs/28777>\
**Category:** General Usage\
**Created:** [September 15, 2019, 1:47am UTC](https://discourse.julialang.org/t/finalizer-only-works-with-mutable-structs/28777 "2019-09-15T01:47:50Z")\
**Posts on this page:** 20\
**Page:** 2

<div class="post-metadata">

**Author:** ![jameson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jameson/32/23_2.png) [@jameson](https://discourse.julialang.org/u/jameson)\
**Post date:** [September 16, 2019, 1:59pm UTC](https://discourse.julialang.org/t/finalizer-only-works-with-mutable-structs/28777/21 "2019-09-16T13:59:13Z")

</div>

> [@yuyichao](#):
>
> Since the object needs to survive beyond the `ccall` to `submit_callback_function` , I’m already storing a reference separately

What reference are you storing though? An immutable object doesn’t have a reference (it may have many). You can always use `Ref(x)` to make a strongly-typed stable reference however (e.g. `let x = Ref(x); GC.@preserve x begin; ccall(..., (Ptr{Cvoid},), x); ...; otheruse(x); end`) and also attach `finalize` to it and so on. It’s nothing particularly special though, just a `mutable struct` itself. (there’s also a lot of similar options, such as `Ref{Any}(x)` and `(Ref{T},)` just depending on what’s appropriate and convenient).

---

<div class="post-metadata">

**Author:** ![leethargo](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/leethargo/32/6004_2.png) [@leethargo](https://discourse.julialang.org/u/leethargo)\
**Post date:** [September 17, 2019, 9:41am UTC](https://discourse.julialang.org/t/finalizer-only-works-with-mutable-structs/28777/22 "2019-09-17T09:41:48Z")

</div>

> [@jameson](#):
>
> What reference are you storing though?

I didn’t mean reference literally, as in `Ref`. It’s actually a `mutable struct` now, which I store in a `Dict` where I know it will survive all future uses.

Unfortunately, I don’t think I can use the `GC.@preserve` block in my case, as the other uses (besides the `ccall` are not in the same scope at all.

If there is interest in this use case, I can mock up some simplified C header with Julia wrapper.

EDIT: I found that this case is already handled well by the [blog post](https://julialang.org/blog/2013/05/callback#passing-closures-in-data-structures) on C callbacks, linked from the Julia docs.

---

<div class="post-metadata">

**Author:** ![Mikhail\_Kagalenko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mikhail_kagalenko/32/13257_2.png) [@Mikhail\_Kagalenko](https://discourse.julialang.org/u/Mikhail_Kagalenko)\
**Post date:** [October 9, 2019, 2:38pm UTC](https://discourse.julialang.org/t/finalizer-only-works-with-mutable-structs/28777/23 "2019-10-09T14:38:23Z")

</div>

> You almost never want to call `pointer_to_objref` yourself.  
> (If you are calling it, you are likely doing it wrong for mutable types as well)

OK, suppose I have a C function that accepts array of pointers to structs:

```c
typedef struct
{
 ...
} _M;

typedef _M *m_t;

void
test_struct(m_t *str_arr)
{
   ...
}

```

How do I call it from Julia? I verified that

```julia
mutable struct M
    ...
end

m = Array{M}(undef,N)
m_p = Array{Ptr{M}}(undef,N)
for n = 1:N
    m[n] = M()
    m_p[n] = pointer_from_objref(m[n])
end

ccall((:test_struct, :mylib), Cvoid, (Ref{Ptr{M}},), m_p)

```

works. Is that not the right way?

---

<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:** [October 9, 2019, 7:13pm UTC](https://discourse.julialang.org/t/finalizer-only-works-with-mutable-structs/28777/24 "2019-10-09T19:13:42Z")

</div>

No it’s not. For anything GC related, you can **never** verify that something work by running it. **NEVER**. This is due to the nature of GC running **very** infrequenty and things can easily appear to work since neither the compiler or the GC is actively trying to exploit the wrong code. Both of them just don’t care about what you have. They are just trying to reduce the amount of work and would not by default do the extra work required to make bad code crash.

For your case, there’s no reason `m` is kept alive at any point and `m_p[n]` is allowed to be completely garbage pointers.

In general, you should call `cconvert` and `unsafe_convert` to populate your `m` and `m_p` and then keep `m` alive during the `ccall` with `GC.@preserve`. i.e. `m[n] = Base.cconvert(Ptr{M}, M()); m_p[n] = Base.unsafe_convert(Ptr{M}, m[n])`.

In this case, if you know `M` is mutable, you can indeed reimplement `cconvert` and `unsafe_convert` yourself.That is indeed what you did and you are just missing the code to keep `m` alive.

That’s also why I said “almost”. It’s basically for the case that you know what `cconvert` and `unsafe_convert` would do and prefer to reimplement them yourself for one reason or another. You generally only care about this if you care about the (type of the) return value of `cconvert` (which you kind of do in this case).

---

<div class="post-metadata">

**Author:** ![Mikhail\_Kagalenko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mikhail_kagalenko/32/13257_2.png) [@Mikhail\_Kagalenko](https://discourse.julialang.org/u/Mikhail_Kagalenko)\
**Post date:** [October 9, 2019, 8:11pm UTC](https://discourse.julialang.org/t/finalizer-only-works-with-mutable-structs/28777/25 "2019-10-09T20:11:02Z")

</div>

Thank you, I understand about GC issue, but not the rest.  
The manual says

> Neither `convert` nor `cconvert` should take a Julia object and turn it into a `Ptr` .  
> However the call

```julia
 m[n] = Base.cconvert(Ptr{M}, M()); 

```

does just that?

Secondly, the unsafe\_convert converts Ptr{M} to Ptr{M} ?

Structure M has pointer to memory that must be initialized by a C library, and from the reading of discussions here I understood, perhaps incorrectly, that the only way to do that is to make it mutable.  
(M is really BigInt)

---

<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:** [October 9, 2019, 9:06pm UTC](https://discourse.julialang.org/t/finalizer-only-works-with-mutable-structs/28777/26 "2019-10-09T21:06:15Z")

</div>

> [@Mikhail\_Kagalenko](#):
>
> > However the call
> 
> ```julia
> m[n] = Base.cconvert(Ptr{M}, M()); 
> 
> ```
> 
> does just that?

No. `m` is a vector of `M` and `cconvert` did not return a pointer.

> [@Mikhail\_Kagalenko](#):
>
> Secondly, the unsafe\_convert converts Ptr{M} to Ptr{M} ?

No, it converts `M` to `Ptr{M}`, essentially by calling `pointer_from_objref`.

> [@Mikhail\_Kagalenko](#):
>
> that the only way to do that is to make it mutable.  
> (M is really BigInt)

No. You can get C initialized struct with pointer field however you want. You just can’t transfer the ownership of that pointer to julia and use finalizer on the object to manage that pointer without having a mutable object to own that memory.

---

<div class="post-metadata">

**Author:** ![Mikhail\_Kagalenko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mikhail_kagalenko/32/13257_2.png) [@Mikhail\_Kagalenko](https://discourse.julialang.org/u/Mikhail_Kagalenko)\
**Post date:** [October 9, 2019, 9:24pm UTC](https://discourse.julialang.org/t/finalizer-only-works-with-mutable-structs/28777/27 "2019-10-09T21:24:40Z")

</div>

> No. `m` is a vector of `M` and `cconvert` did not return a pointer.

Sorry, should have read the source. For Type{\<:Ptr} convert is noop, so that was what you meant by " if you know `M` is mutable, you can indeed reimplement `cconvert` and `unsafe_convert` yourself.That is indeed what you did and you are just missing the code to keep `m` alive." Although, where does the mutability enter into it?

> You can get C initialized struct with pointer field however you want.

In a constructor of an immutable type I should get initialized memory somehow. What can I pass to a C initializer function other than a pointer to a mutable type that mirrors the definition of an immutable type?

---

<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:** [October 9, 2019, 9:35pm UTC](https://discourse.julialang.org/t/finalizer-only-works-with-mutable-structs/28777/28 "2019-10-09T21:35:29Z")

</div>

> [@Mikhail\_Kagalenko](#):
>
> Although, where does the mutability enter into it?

Because I shouldn’ve said `Ref{M}` instead of `Ptr{M}` = = …  
And then you can see that for immutable type `cconvert` isn’t a no-op… = = …

> [@Mikhail\_Kagalenko](#):
>
> In a constructor of an immutable type I should get initialized memory somehow. What can I pass to a C initializer function other than a pointer to a mutable type that mirrors the definition of an immutable type?

You will not be construct that object in julia, you let C fill in the memory and you load that object in julia. The memory can either be julia (managed) memory or C (unmanaged) memory and it can either be allocated in julia or in C.

---

<div class="post-metadata">

**Author:** ![Mikhail\_Kagalenko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mikhail_kagalenko/32/13257_2.png) [@Mikhail\_Kagalenko](https://discourse.julialang.org/u/Mikhail_Kagalenko)\
**Post date:** [October 9, 2019, 11:04pm UTC](https://discourse.julialang.org/t/finalizer-only-works-with-mutable-structs/28777/29 "2019-10-09T23:04:42Z")

</div>

> [@yuyichao](#):
>
> Because I shouldn’ve said `Ref{M}` instead of `Ptr{M}`  
> And then you can see that for immutable type `cconvert` isn’t a no-op

`cconvert(Ref{M}, M())` is not a no-op for a mutable M as well, so it is not clear to me what exactly you have in mind here

> You can get C initialized struct with pointer field however you want.

OK, then in an immutable constructor I may do something like

```julia
m = Array{UInt8}(undef,sizeof(M))
mp=Base.unsafe_convert(Ref{M},m)
ccall((:struct_init, :mylib), Cvoid, (Ref{M},), mp)
unsafe_load(mp,1)

```

which does seem to get correctly initialized memory, but contradicts documentation, by not passing to unsafe\_convert the output of cconvert

```julia

```

---

<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:** [October 10, 2019, 12:01am UTC](https://discourse.julialang.org/t/finalizer-only-works-with-mutable-structs/28777/30 "2019-10-10T00:01:05Z")

</div>

> [@Mikhail\_Kagalenko](#):
>
> so it is not clear to me what exactly you have in mind here

The implementations of the two convertion functions together is effectively the same as a no-op plus a `pointer_from_objref`.

> [@Mikhail\_Kagalenko](#):
>
> m = Array{UInt8}(undef,sizeof(M))

Just a `Ref` would work. If anything, you should use `Array{M}`

> [@Mikhail\_Kagalenko](#):
>
> but contradicts documentation, by not passing to unsafe\_convert the output of cconvert

Err, which part contradicts the document? The document didn’t say what would **NOT** work, it only says what **would** work. What you have is indeed not what the document says should work but that just mean it may not be well defined code. It doesn’t mean the code would not work or would not appear to work.

In your code, you are still not garanteed to get a valid pointer out of `m`, i.e. `mp` could be garbage since you still failed to keep `m` alive.

According to the document and using each conversion functions as well as the `unsafe_load` explicitly, you need,

```julia
m = Ref{M}()
mc = Base.cconvert(Ref{M}, m) # Converting to `Ptr{M}` is fine here to as long as it agrees with below.
mp = Base.unsafe_convert(Ref{M}, mc)
GC.@preserve m begin
    ccall(....., mp)
    return unsafe_load(mp)
end

```

Now you don’t have to do the `unsafe_load` manually since you have access to the julia object, you can just do `m[]` whether `m` is a `RefValue{M}` or `Vector{M}`.

You also don’t have to do all the conversion explicitly, the code with `unsafe_/cconvert` and `GC.@preserve` above is basically an expansion of `ccall(..., m)` (not how things are implemented but effectively the same) so you ony need `m = Ref{M}(); ccall(..., m); return m[]`

---

<div class="post-metadata">

**Author:** ![Mikhail\_Kagalenko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mikhail_kagalenko/32/13257_2.png) [@Mikhail\_Kagalenko](https://discourse.julialang.org/u/Mikhail_Kagalenko)\
**Post date:** [October 10, 2019, 10:43am UTC](https://discourse.julialang.org/t/finalizer-only-works-with-mutable-structs/28777/31 "2019-10-10T10:43:32Z")

</div>

Thank you for this excellent explanation. So

```julia
m = Ref{M}()

```

“This type is guaranteed to point to valid, Julia-allocated memory of the correct type.” And that must hold for immutable types, as well, since documentation does not say otherwise.

Is it possible to manually trigger memory corruption without GC.preserve ? I tried  
`GC.gc(true)`  
but the code still runs

---

<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:** [October 10, 2019, 11:39am UTC](https://discourse.julialang.org/t/finalizer-only-works-with-mutable-structs/28777/32 "2019-10-10T11:39:11Z")

</div>

> [@Mikhail\_Kagalenko](#):
>
> “This type is guaranteed to point to valid, Julia-allocated memory of the correct type.” And that must hold for immutable types, as well, since documentation does not say otherwise.

No. It’s just a normal type. What you get by converting it to a pointer of the correct pointer/ref type is a pointer to a memory that can hold the correct type. The pointer you get may not **have** the correct type (it may not have the tag or the correct one and calling `jl_typeof` on it in C will not give you the “correct” answer).

> [@Mikhail\_Kagalenko](#):
>
> Is it possible to manually trigger memory corruption without GC.preserve ? I tried  
> `GC.gc(true)`  
> but the code still runs

Not in general. The compiler also may or may not decide tell the GC that certain objects aren’t used by your code anymore.

---

<div class="post-metadata">

**Author:** ![Mikhail\_Kagalenko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mikhail_kagalenko/32/13257_2.png) [@Mikhail\_Kagalenko](https://discourse.julialang.org/u/Mikhail_Kagalenko)\
**Post date:** [October 10, 2019, 12:47pm UTC](https://discourse.julialang.org/t/finalizer-only-works-with-mutable-structs/28777/33 "2019-10-10T12:47:32Z")

</div>

> [@yuyichao](#):
>
> No. It’s just a normal type.

“It” here refers to the result of calling `Ref{M}()` ?  
So looking at the source, what it does is just put `M` inside the struct and create that struct without calling constructor for `M`:

`RefValue{T}() where {T} = new()`

that new() call applies to RefValue struct, so I guess its implementation just reserves `sizeof(M)` bytes within RefValue instance and claims to Julia that it is M, without actually writing anything into that memory. Correct? Then the documentation could be clearer on that point, I think.

---

<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:** [October 10, 2019, 1:32pm UTC](https://discourse.julialang.org/t/finalizer-only-works-with-mutable-structs/28777/34 "2019-10-10T13:32:50Z")

</div>

> [@Mikhail\_Kagalenko](#):
>
> “It” here refers to the result of calling `Ref{M}()` ?

Yes.

> [@Mikhail\_Kagalenko](#):
>
> So looking at the source, what it does is just put `M` inside the struct and create that struct without calling constructor for `M` :
> 
> `RefValue{T}() where {T} = new()`
> 
> that new() call applies to RefValue struct, so I guess its implementation just reserves `sizeof(M)` bytes within RefValue instance and claims to Julia that it is M, without actually writing anything into that memory. Correct? Then the documentation could be clearer on that point, I think.

AFAICT, what you said was just a somewhat ok but somewhat inaccurate description of creating an type with a single field `M`.

Also, I’m not sure what you know and what are you trying to understand now. What you’ve said so far has a mix of different levels (the julia code level and implementation level). Without knowing what you want and what you know, it’s very hard to judge exactly what you meant and what you want to get out of it/what you want to confirm.

For example, both of “Julia-allocated memory of the correct type” and “claims to Julia that it is M” are very vague. They can both be correct or incorrect based on how you interpret them but the correct interpretation might not be how you interpreted them.

---

<div class="post-metadata">

**Author:** ![Mikhail\_Kagalenko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mikhail_kagalenko/32/13257_2.png) [@Mikhail\_Kagalenko](https://discourse.julialang.org/u/Mikhail_Kagalenko)\
**Post date:** [October 10, 2019, 8:21pm UTC](https://discourse.julialang.org/t/finalizer-only-works-with-mutable-structs/28777/35 "2019-10-10T20:21:55Z")

</div>

Mostly I am trying to understand the memory handling from the point of view of mainly C programmer, who studied Julia for about a week.

So in the simplest version

```julia
m=Ref{M}()
ccall(...,(Ref{M}),m)
return m[]

```

it’s the usage of m after ccall that protects m from GC and without it the ccall might fail?

---

<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:** [October 10, 2019, 11:04pm UTC](https://discourse.julialang.org/t/finalizer-only-works-with-mutable-structs/28777/36 "2019-10-10T23:04:00Z")

</div>

> [@Mikhail\_Kagalenko](#):
>
> Mostly I am trying to understand the memory handling from the point of view of mainly C programmer, who studied Julia for about a week.

I think it’s the best to understand what julia garantees in terms of memory manangement and trying to separate it out from the implementation…

There are multiple layers happening at the same time.

You need to first understand that in julia objects are not related to addresses so until you are converting something to a C pointer, it doesn’t make sense to talk about addresses (Julia will find somewhere to store your data and you can learn the internal to figure out how it’ll do it but that has no significance and isn’t something you can rely one).

Then you can learn what basic pointer conversions there are. This includes `pointer` and `pointer_from_objref` and what’s the object memory layout they expose to you. This is also where the user-facing API’s (`cconvert` and `unsafe_convert`) lies. Basically `cconvert` and `unsafe_convert` on `Ptr` and `Ref` are wrappers around `pointer` and `pointer_from_objref` in one way or another. You’ll also understand here the ownership of the pointer you get. For correct implementation of the functions, the result of `pointer` and `pointer_from_objref` belongs to the argument. This is not always possible (immutable types basically can’t) so generically, `cconvert` returns an object that’s the owner of the pointer returned by calling `unsafe_convert` on it.

Finally, you need to know what liveness guanrantee julia provides. There are basically 3 in pure julia, `GC.@preserve`, `ccall` and global variable. As long as the owner of the memory is guaranteed rooted/preserved by one of the three, you can use the pointer.  
As an example, if you have `a = Vector{Float64}(...); GC.@preserve a begin p = pointer(a); <...> end` then within `<...>` you can use `p` however you want and it is guaranteed to be correspond to the content of `a`. Similarly, if you have `ccall(...., a)` and if the `unsafe_convert` and `cconvert` are defined correctly for `a`, then there won’t be any problems. (and also similar for global varables)

> [@Mikhail\_Kagalenko](#):
>
> it’s the usage of m after ccall that protects m from GC and without it the ccall might fail?

No. I believe the `ccall` document described this in detail (also see above), `ccall` guarantees that the return value of `cconvert` is live throught the whole call. The `m` after the call **NEVER** has any significance in determining the lifetime as far as the semantics is concerned. In reality it could, which is why if you do `ccall(..., pointer_from_objref(m)); return m[]` it could actually work even though it’s completely invalid code.

---

<div class="post-metadata">

**Author:** ![Mikhail\_Kagalenko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mikhail_kagalenko/32/13257_2.png) [@Mikhail\_Kagalenko](https://discourse.julialang.org/u/Mikhail_Kagalenko)\
**Post date:** [October 11, 2019, 1:51pm UTC](https://discourse.julialang.org/t/finalizer-only-works-with-mutable-structs/28777/37 "2019-10-11T13:51:25Z")

</div>

> The `m` after the call **NEVER** has any significance in determining the lifetime

How so? The GC can’t eliminate the objects while they are still being used, can it?

---

<div class="post-metadata">

**Author:** ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)\
**Post date:** [October 11, 2019, 2:09pm UTC](https://discourse.julialang.org/t/finalizer-only-works-with-mutable-structs/28777/38 "2019-10-11T14:09:57Z")

</div>

> [@Mikhail\_Kagalenko](#):
>
> How so? The GC can’t eliminate the objects while they are still being used, can it?

What “being in use” means is a bit fuzzy. The compiler can reorder things, pick apart things, remove things from ever existing, etc however it wants. The only correct way to influence lifetime is the ways that have been stated.

---

<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:** [October 11, 2019, 4:14pm UTC](https://discourse.julialang.org/t/finalizer-only-works-with-mutable-structs/28777/39 "2019-10-11T16:14:07Z")

</div>

> [@Mikhail\_Kagalenko](#):
>
> The GC can’t eliminate the objects while they are still being used, can it?

The GC doesn’t care a little bit about object. The GC cares about allocations.  
So yes, the GC cannot eliminate an allocation if it’s still being used. So if `m` was allocated before the `ccall` and used after the `ccall` and if the use after the `ccall` didn’t get eliminated the GC won’t free the **allocation**.

However, an allocation is completely different from an object. The compiler takes care of that and in this case it doesn’t have to satisfy basically any of the conditions above. The compiler can decide to not allocate `m` before the `ccall`, or not at all, it can decide the use of `m` after the `ccall` is dead and eliminate it. There are many different possibilities and most of them (including the separation of the work between the compiler and the GC) are just implementation detail of the language. That’s why I said you should understand each layer separately and stick to the actual guarantee.

It’s the same deal as UB in C. If the compiler didn’t think it’s worth messing with you, you can write code with UB that appears to work. Once in a while though, the compiler will find a smart way to surprise you.

---

<div class="post-metadata">

**Author:** ![foobar\_lv2](https://avatars.discourse-cdn.com/v4/letter/f/ee59a6/32.png) [@foobar\_lv2](https://discourse.julialang.org/u/foobar_lv2)\
**Post date:** [October 13, 2019, 1:32pm UTC](https://discourse.julialang.org/t/finalizer-only-works-with-mutable-structs/28777/40 "2019-10-13T13:32:02Z")

</div>

Ok, to clarify. With complete code, consider

```julia
typedef struct MS {int c;} M;

extern void foo(M** arg){
    (*arg)->c = 1;
    return;
}

```

compiled via

```julia
$ clang -shared -fpic foo.c -o foolib.so

```

Now let’s do the julia side:

```julia
julia> mutable struct M
       x::Cint
       end

julia> arr=[M(2) for i=1:3]
3-element Array{M,1}:
 M(2)
 M(2)
 M(2)

julia> h(arr, i) = ccall((:foo, "./foolib.so"), Cvoid, (Ptr{Ptr{M}},), pointer(arr, i));

julia> h(arr, 1); arr
3-element Array{M,1}:
 M(1)
 M(2)
 M(2)

```

That works as expected, and is valid when called from the REPL, but is invalid when called from a compiled context, due to gc issues: No one keeps `arr` alive. We can fix this by

```julia
julia> h_gc(arr, i) = GC.@preserve arr ccall((:foo, "./foolib.so"), Cvoid, (Ptr{Ptr{M}},), pointer(arr, i));

```

Both compile down to identical `@code_native`, but behave different when inlined.

If we were too lazy to deal with the entire `GC.@preserve` dance, we could also

```julia
@noinline h_ni(arr, i) = ccall((:foo, "./foolib.so"), Cvoid, (Ptr{Ptr{M}},), pointer(arr, i));

```

right @yuyichao?

I.e. just put a `@noinline` function barrier outside of contexts where we take pointers and trust that the calling context keeps our stuff alive? Or is the compiler allowed to IPO through `@noinline` function barriers? (besides of caller knowing llvm attributes of the callee, which should be ok)

For other people reading at home, the `@code_native h(arr, 1)` is a mess on 1.2.0, which is fixed in [https://github.com/JuliaLang/julia/commit/350f514a91ab29b74cb2f81d0a7a134b8ac283bb](https://github.com/JuliaLang/julia/commit/350f514a91ab29b74cb2f81d0a7a134b8ac283bb)  
. (we had `Base.pointer` → `Base.elsize` → `Core.sizeof(Ptr)`, which didn’t constant-fold and should never ever have been called; now it is `Core.sizeof(Ptr{Cvoid})` which is a concrete type and inlines properly).

[Previous page](https://discourse.julialang.org/t/finalizer-only-works-with-mutable-structs/28777.md?page=1)

[Next page](https://discourse.julialang.org/t/finalizer-only-works-with-mutable-structs/28777.md?page=3)
