Crystal: Object created by Box.box is being collected by GC

Created on 12 Aug 2016  路  3Comments  路  Source: crystal-lang/crystal

Hi, I've been trying to pass a Proc to a C function by way described in Proc's recipe but results I'm getting are outside of the scope of my understanding :)

In the proc literal called from C I've got:

data_as_callback = Box(typeof(callback)).unbox(data)

When it gets called data (Box-ed Proc pointer I guess?) is still the same, but data_as_callback randomly returns different (strange?) results:

data             # => Pointer(Void)@0x1073ff0a0
data_as_callback # => #<Proc(String, Nil):0x0>

Then l8r on:

data             # => Pointer(Void)@0x1073ff0a0
data_as_callback # => #<Proc(String, Nil):0x18:closure>

Executing data_as_callback.call (obviously) fails with:

Invalid memory access (signal 11) at address 0x18
[4392606203] *CallStack::print_backtrace:Int32 +107
[4392506423] __crystal_sigfault_handler +55
[140735736141098] _sigtramp +26

Am I doing sth wrong?

PS. I was saving callback as an instance property, class property and global variable, all without success. It works if instead of using Box.box I'll pass foo.as(Void*) as data, and then inside of proc literal, I'll "unbox" it via back_to_self = data.as(Foo) and call back_to_self.my_callback.call.

bug docs

Most helpful comment

Ok, I think I've found the culprit: Proc docs state that one needs to save the callback in Crystal-land so GC doesn't collect it, but it seems that GC is collecting Box object created by Box.box instead. A quick solution (I'm not sure if correct though) would be to save in ivar boxed_data instead of callback.

All 3 comments

Ok, I think I've found the culprit: Proc docs state that one needs to save the callback in Crystal-land so GC doesn't collect it, but it seems that GC is collecting Box object created by Box.box instead. A quick solution (I'm not sure if correct though) would be to save in ivar boxed_data instead of callback.

@Sija is right, I think the docs are incorrect.

One must store a reference to the box, not to the callback itself. E.g.

@@boxed_data = Box.box(callback)

I think you are right, the GC doesn't own the data behind Box, so it assumes it can delete the Box. I'll do some tests to check this, and later fix the docs.

Was this page helpful?
0 / 5 - 0 ratings