# 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:** 3

<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 13, 2019, 10:19pm UTC](https://discourse.julialang.org/t/finalizer-only-works-with-mutable-structs/28777/41 "2019-10-13T22:19:00Z")

</div>

> [@foobar\_lv2](#):
>
> 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?

I would not rely on that in the long term.

---

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

</div>

So having figured out, I think, passing array of pointers to structs, I got stuck passing array of 1-element arrays. The C function I need to use has the interface like this test function

```julia
typedef struct
{
  int a;
} _M;

typedef _M m_t[1];

void
print_M_arr(int N, m_t *ptr)
{
  for( int n = 0; n < N; n++) {
   fprintf(stdout, "M[%d]->a: %d\n",n, ptr[n]->a);
  }
}

```

And the on the Julia side,

```julia
mutable struct M
    a :: Cint
end
N=3
m = [[M(n)] for n = 1:N]
m_p = [Base.unsafe_convert(Ref{M},Base.cconvert(Ref{M},m[n])) for n = 1:N]

GC.@preserve m begin
    ccall((:print_M_arr, "./libmp_test"), Cvoid, (Cint, Ref{Ptr{M}},), N, m_p)
end

```

That prints garbage. I didn’t find any recent tips on how to do this call.

---

<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 14, 2019, 11:14pm UTC](https://discourse.julialang.org/t/finalizer-only-works-with-mutable-structs/28777/43 "2019-10-14T23:14:53Z")

</div>

> [@Mikhail\_Kagalenko](#):
>
> ```julia
> m_p = [Base.unsafe_convert(Ref{M},Base.cconvert(Ref{M},m[n])) for n = 1:N]
> 
> ```

Again, be aware that this can return completely garbage since the return value of `cconvert(Ref{M}, ...)` is not kept safe anywhere. But thtat’s probably not what’s causing the issue.

> [@Mikhail\_Kagalenko](#):
>
> ```julia
> ccall((:print_M_arr, "./libmp_test"), Cvoid, (Cint, Ref{Ptr{M}},), N, m_p)
> 
> ```

And no, this is the wrong type. I get that this is due to one of the biggest misconception people have in C,

Array type and pointer type are **NOT** the same thing. Again, they are **NOT** the same.

What you have in your C code is simply a pointer to an **array** type and the pointer is pointing to the array, not the pointer to the array. You do not have a pointer to a **pointer** type, which is what you’ve created in julia. What you need is simply a pointer to `M`.

---

<div class="post-metadata">

**Author:** ![c42f](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/c42f/32/52842_2.png) [@c42f](https://discourse.julialang.org/u/c42f)\
**Post date:** [October 15, 2019, 6:44am UTC](https://discourse.julialang.org/t/finalizer-only-works-with-mutable-structs/28777/44 "2019-10-15T06:44:05Z")

</div>

> [@Mikhail\_Kagalenko](#):
>
> The C function I need to use has the interface like this test function
> 
> […]
> 
> ```C
> void print_M_arr(int N, m_t *ptr)
> 
> ```

This C signature is certainly incompatible with `[[M(n)] for n = 1:N]` as you’ve found out, but how close is this to what you’re really trying to do? These things are subtle and we could give more precise help if you post the real interface you’re trying to call rather than a toy example.

---

<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 15, 2019, 10:07am UTC](https://discourse.julialang.org/t/finalizer-only-works-with-mutable-structs/28777/45 "2019-10-15T10:07:14Z")

</div>

> [@yuyichao](#):
>
> Array type and pointer type are **NOT** the same thing. Again, they are **NOT** the same.

Yes, I know that. In fact, I wrote that passing array of pointers to structs works in the very message you replied to.

> [@yuyichao](#):
>
> What you need is simply a pointer to `M` .

Well, I did try

```julia
m = [M(n) for n = 1:N]
GC.@preserve m begin
    m_p=Base.unsafe_convert(Ref{M},Base.cconvert(Ref{M},m))
    ccall((:print_M_arr, "./libmps_calls"), Cvoid, (Cint, Ref{M},), N, m_p)
end

```

The type of m\_p here is `Ptr{M}`, that prints garbage as well.

---

<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 15, 2019, 10:11am UTC](https://discourse.julialang.org/t/finalizer-only-works-with-mutable-structs/28777/46 "2019-10-15T10:11:31Z")

</div>

> [@c42f](#):
>
> but how close is this to what you’re really trying to do?

It is almost exacly what I am tring to call. Really it is the  
`mpq_t` type from GNU GMP library. In Julia that would translate to struct containing two immutable structs. I am pretty sure that once the example works, the rest should fall into place.

---

<div class="post-metadata">

**Author:** ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)\
**Post date:** [October 15, 2019, 10:38am UTC](https://discourse.julialang.org/t/finalizer-only-works-with-mutable-structs/28777/47 "2019-10-15T10:38:39Z")

</div>

With the danger of you already knowing, Julias `BigInt`s are GMP backed (see [here](https://docs.julialang.org/en/v1/base/numbers/#BigFloats-and-BigInts-1)).

---

<div class="post-metadata">

**Author:** ![c42f](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/c42f/32/52842_2.png) [@c42f](https://discourse.julialang.org/u/c42f)\
**Post date:** [October 15, 2019, 11:51am UTC](https://discourse.julialang.org/t/finalizer-only-works-with-mutable-structs/28777/48 "2019-10-15T11:51:30Z")

</div>

> [@Mikhail\_Kagalenko](#):
>
> Really it is the `mpq_t` type from GNU GMP library. In Julia that would translate to struct containing two immutable structs.

Ah hah, thanks. You’re right that this case should be modeled as a struct containing two immutable structs. Let’s consider `mpq_init` from [Initializing Rationals (GNU MP 6.3.0)](https://gmplib.org/manual/Initializing-Rationals.html#Initializing-Rationals). From the GMP header we have

```C
typedef struct
{
  __mpz_struct _mp_num;
  __mpz_struct _mp_den;
} __mpq_struct;

typedef __mpq_struct *mpq_ptr;

typedef __mpq_struct mpq_t[1];

void __gmpq_init (mpq_ptr); // Documented as taking `mpq_t` but that's equivalent

```

I expect the `mpq_t` typedef is really just a convenience which allows declaring local variables in `C` as `mpq_t`. The actual header uses `mpq_ptr` here rather than `mpq_t` for `mpq_init` (real name `__gmpq_init`) but those are equivalent in this usage.

To call from Julia, do something like:

```julia
struct MPZ
    alloc::Cint
    size::Cint
    d::Ptr{Base.GMP.Limb}
end

mutable struct MPQ
    num::MPZ
    den::MPZ

    function MPQ()
        mpq = new()
        ccall((:__gmpq_init, :libgmp), Cvoid, (Ref{MPQ},), mpq)
        # TODO: add finalizer!
        mpq
    end
end

mpq = MPQ()

# Set value from string
ccall((:__gmpq_set_str, :libgmp), Cint, (Ref{MPQ}, Cstring, Cint), mpq, "41/152", 10)

# Invert
ccall((:__gmpq_inv, :libgmp), Cvoid, (Ref{MPQ}, Ref{MPQ}), mpq, mpq)

# Get string representation (FIXME: This current leaks memory!)
unsafe_string(ccall((:__gmpq_get_str, :libgmp), Cstring, (Cstring, Cint, Ref{MPQ}), C_NULL, 10, mpq))

```

---

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

</div>

> [@Mikhail\_Kagalenko](#):
>
> In fact, I wrote that passing array of pointers to structs works in the very message you replied to.

What do you mean? I’m a little confused why you are trying to pass with more level of pointers then…

> [@Mikhail\_Kagalenko](#):
>
> ```julia
> GC.@preserve m begin 
> m_p=Base.unsafe_convert(Ref{M},Base.cconvert(Ref{M},m))
> 
> ```

Again, this is wrong. You need to preserve the **return value of `cconvert`**. Also, you almost never need to write out the conversion explicitly with `ccall`. Doing it explicitly and doing it wrong just make it worse. But anyway, that’s now why you get garbage.

> [@Mikhail\_Kagalenko](#):
>
> The type of m\_p here is `Ptr{M}`

This doesn’t matter. What matters is how you get the pointer. This one is a case (I think there’s an issue for it) that the default conversion allows the conversion in cases that it really shouldn’t. Your `m` is an array of reference, (array of pointer) in memory. Since `M` is mutable, it’s impossible to pass an array of `M` as C array, the memory layout is completely incompatible. You have to use immutable type here.

---

<div class="post-metadata">

**Author:** ![c42f](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/c42f/32/52842_2.png) [@c42f](https://discourse.julialang.org/u/c42f)\
**Post date:** [October 15, 2019, 12:11pm UTC](https://discourse.julialang.org/t/finalizer-only-works-with-mutable-structs/28777/50 "2019-10-15T12:11:54Z")

</div>

Having said all that about how to call into GMP, I should point out that Julia has native support for big rationals:

```julia
julia> q = big(41//152)
41//152

julia> 1/q
152//41

julia> q^15
1555098314991537910888601//534138422146939893094821310496768

```

---

<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 15, 2019, 1:03pm UTC](https://discourse.julialang.org/t/finalizer-only-works-with-mutable-structs/28777/51 "2019-10-15T13:03:37Z")

</div>

Passing a single mpq\_t is not a problem, that works both with the simplified example and the mpq\_t type. However, as I stated above, I am trying to use a function that accepts and returns **arrays** of mpq\_t

---

<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 15, 2019, 1:05pm UTC](https://discourse.julialang.org/t/finalizer-only-works-with-mutable-structs/28777/52 "2019-10-15T13:05:08Z")

</div>

Julia’s Rational{BigInt} is not interoperable with mpq\_t, though.

---

<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 15, 2019, 1:18pm UTC](https://discourse.julialang.org/t/finalizer-only-works-with-mutable-structs/28777/53 "2019-10-15T13:18:29Z")

</div>

> [@yuyichao](#):
>
> What do you mean?

In my first reply in this discussion I gave an example.

> [@yuyichao](#):
>
> Since `M` is mutable, it’s impossible to pass an array of `M` as C array, the memory layout is completely incompatible. You have to use immutable type here.

I understand why it is impossible to pass an array where structures are located sequentially in memory, unless Julia structs are immutable. But does the type of C call `print_m(int N, m_t *arr)` imply that the structures are located in one contiguous block of memory? The `arr[n]` value in C code is a pointer to struct, not the struct. On the other hand, `sizeof(m_t)` will be equal to the size of the struct, not the pointer, so maybe that is the issue with my code.

---

<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 15, 2019, 2:20pm UTC](https://discourse.julialang.org/t/finalizer-only-works-with-mutable-structs/28777/54 "2019-10-15T14:20:48Z")

</div>

> [@Mikhail\_Kagalenko](#):
>
> In my first reply in this discussion I gave an example.

Well, if you meant that you know the C code you give for pointer to array is different from the previous post of pointer to pointer, then yes, you are correct. However, it appears that you still got that wrong. You are adding one more level of indirection in the julia code for the pointer to array than the pointer to pointer. In reality, you should remove one level of indirection.

> [@Mikhail\_Kagalenko](#):
>
> imply that the structures are located in one contiguous block of memory?

Yes, that’s exactly what I said. (See below)

> [@Mikhail\_Kagalenko](#):
>
> The `arr[n]` value in C code is a pointer to struct, not the struct.

Nope, it’s not. It’s an **array** of the struct, **not** a **pointer** to the struct. Again, array and pointer are different in C. C just have some very relaxed rule for array to pointer type decay which makes it possible for you to treat array as pointers when passing them arround. They are completely different when you are dealing with object layout.

---

<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 15, 2019, 2:25pm UTC](https://discourse.julialang.org/t/finalizer-only-works-with-mutable-structs/28777/55 "2019-10-15T14:25:44Z")

</div>

> [@yuyichao](#):
>
> > The `arr[n]` value in C code is a pointer to struct, not the struct.
> 
> Nope, it’s not. It’s an **array** of the struct, **not** a **pointer** to the struct.

The name of array in C code decays to the pointer to its first element, so in C code `arr[n]` is a pointer to the struct.  
[http://c-faq.com/aryptr/aryptrequiv.html](http://c-faq.com/aryptr/aryptrequiv.html)

---

<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 15, 2019, 2:31pm UTC](https://discourse.julialang.org/t/finalizer-only-works-with-mutable-structs/28777/56 "2019-10-15T14:31:19Z")

</div>

Nope. `arr[n]` is not a name. (edit: actually I’m not sure about the not a name part, but it is not a pointer for sure…)

```julia
yyc:~/tmp
yuyichao% cat a.c
//

struct A {
    char a[100];
};

typedef struct A AA[1];

int f(AA *aa)
{
    return sizeof(aa[0]);
}
yyc:~/tmp
yuyichao% clang a.c -S -emit-llvm -o - -O2
; ModuleID = 'a.c'
source_filename = "a.c"
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-linux-gnu"

%struct.A = type { [100 x i8] }

; Function Attrs: norecurse nounwind readnone sspstrong uwtable
define dso_local i32 @f([1 x %struct.A]* nocapture readnone) local_unnamed_addr #0 {
  ret i32 100
}

attributes #0 = { norecurse nounwind readnone sspstrong uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }

!llvm.module.flags = !{!0, !1, !2}
!llvm.ident = !{!3}

!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{i32 7, !"PIC Level", i32 2}
!2 = !{i32 7, !"PIE Level", i32 2}
!3 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"}

```

---

<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 15, 2019, 2:32pm UTC](https://discourse.julialang.org/t/finalizer-only-works-with-mutable-structs/28777/57 "2019-10-15T14:32:07Z")

</div>

By the way

> [@yuyichao](#):
>
> Again, this is wrong. You need to preserve the **return value of `cconvert`**.

Are you saying that I need to insert another GC.@preserve before ccall?

---

<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 15, 2019, 2:33pm UTC](https://discourse.julialang.org/t/finalizer-only-works-with-mutable-structs/28777/58 "2019-10-15T14:33:23Z")

</div>

No, you don’t need another one, you simply placed the one at the wrong place. You don’t need to do anything about `m`. Again… you only need to preserve the return value of `cconvert`.

---

<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 15, 2019, 2:35pm UTC](https://discourse.julialang.org/t/finalizer-only-works-with-mutable-structs/28777/59 "2019-10-15T14:35:07Z")

</div>

C standard says

> A reference to an object of type array-of-T which appears in an expression decays (with three exceptions) into a pointer to its first element; the type of the resultant pointer is pointer-to-T.

(the three exceptions do not apply here) If Clang doesn’t do that, it is wrong.

---

<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 15, 2019, 2:36pm UTC](https://discourse.julialang.org/t/finalizer-only-works-with-mutable-structs/28777/60 "2019-10-15T14:36:12Z")

</div>

I can tell you with 100% certainty that clang is correct and gcc does the same thing.

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

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