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.
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.
Most helpful comment
Ok, I think I've found the culprit:
Procdocs state that one needs to save thecallbackin Crystal-land so GC doesn't collect it, but it seems that GC is collectingBoxobject created byBox.boxinstead. A quick solution (I'm not sure if correct though) would be to save in ivarboxed_datainstead ofcallback.