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:
Proc
docs state that one needs to save thecallback
in Crystal-land so GC doesn't collect it, but it seems that GC is collectingBox
object created byBox.box
instead. A quick solution (I'm not sure if correct though) would be to save in ivarboxed_data
instead ofcallback
.