# Storing c pointers in ruby hash

**URL:** <https://www.ruby-forum.com/t/storing-c-pointers-in-ruby-hash/167349>\
**Category:** Ruby\
**Created:** [May 6, 2009, 11:00pm UTC](https://www.ruby-forum.com/t/storing-c-pointers-in-ruby-hash/167349 "2009-05-06T23:00:29Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![Rolando\_A](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/d9b06d/32.png) [@Rolando\_A](https://www.ruby-forum.com/u/Rolando_A)\
**Post date:** [May 6, 2009, 11:00pm UTC](https://www.ruby-forum.com/t/storing-c-pointers-in-ruby-hash/167349/1 "2009-05-06T23:00:29Z")

</div>

Hi all,  
I’m been banging my head on the keyboard the whole day trying to track  
a bug.  
I have a embedded ruby (branch 1\_9\_1, checked out today) running on a  
Objective-C project (if anyone’s interested, it’s this project:  
[GitHub - rolandoam/shinycocos: ruby bindings for cocos2d-iphone (a.k.a.: i want to program my iphone game in ruby)](http://github.com/funkaster/shinycocos/tree/master))  
.  
The idea is to keep a reference to the ruby counterpart of the Obj-C  
object. Right now, I’m using a “global” hash table, defined as this:

VALUE sc\_object\_hash = rb\_hash\_new();

The variable has been registered to the GC as suggested in the  
README.EXT:

rb\_global\_variable(&sc\_object\_hash);

An objc object is associated to a new ruby object (the ruby version of  
the objc class) this way:

node = [[SomeClass alloc] init];  
VALUE rb\_obj = common\_init(klass, nil, node, argc, argv, YES);  
common\_link(node, rb\_obj);

common\_init is a function defined as follows:

VALUE common\_init(VALUE klass, cocos\_holder \*\*ret\_ptr, id object, int  
argc, VALUE \*argv, BOOL release\_on\_free) {  
VALUE obj;  
cocos\_holder \*ptr;  
if (release\_on\_free)  
obj = Data\_Make\_Struct(klass, cocos\_holder, 0, common\_free, ptr);  
else  
obj = Data\_Make\_Struct(klass, cocos\_holder, 0,  
common\_free\_no\_release, ptr);  
ptr-\>\_obj = object;  
rb\_obj\_call\_init(obj, argc, argv);  
if (ret\_ptr != nil)  
\*ret\_ptr = ptr;  
return obj;  
}

and common\_link is an inline function:

static inline void common\_link(id obj1, VALUE obj2) {  
rb\_hash\_aset(sc\_object\_hash, INT2FIX((long)obj1), obj2);  
}

Some times, the objc framework will call a method in the objc object.  
When this happens, I need to call the proper ruby method in the  
corresponding ruby object:

- (void)someMethodCalledByTheFramework {  
VALUE rb\_obj = common\_link\_ref(self);  
rb\_funcall(rb\_obj, id\_cb\_on\_enter, 0, 0);  
}

common\_link\_ref is the counterpart of common\_link (basically calls  
rb\_hash\_aref on the same hash)  
The thing is, that the rb\_obj is crashing the ruby interpreter. If I  
try to call any method on it (even inspect) I get a bad access error.  
It was working with a ruby 1.8 version, but now that I’ve ruby 1.9, it  
refuses to work… Any idea of what I could be doing wrong here?  
Is there a better way to link a ruby object with a c pointer? I need  
to get the associated ruby object to a given objc object. Not the  
other way around (which is easy using Data\_Get\_Struct)… that’s why  
I’m using a hash table.

thanks!

---

<div class="post-metadata">

**Author:** ![Rolando\_A](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/d9b06d/32.png) [@Rolando\_A](https://www.ruby-forum.com/u/Rolando_A)\
**Post date:** [May 6, 2009, 11:08pm UTC](https://www.ruby-forum.com/t/storing-c-pointers-in-ruby-hash/167349/2 "2009-05-06T23:08:44Z")

</div>

also, if I try to inspect the contents of the hash, I also get a core  
dump.

On May 6, 2009, at 4:59 PM, Rolando A. wrote:

> common\_link(node, rb\_obj);  
> obj = Data\_Make\_Struct(klass, cocos\_holder, 0,  
> static inline void common\_link(id obj1, VALUE obj2) {  
> }  
> other way around (which is easy using Data\_Get\_Struct)… that’s why  
> I’m using a hash table.

thanks,

---

<div class="post-metadata">

**Author:** ![Rolando\_A](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/d9b06d/32.png) [@Rolando\_A](https://www.ruby-forum.com/u/Rolando_A)\
**Post date:** [May 7, 2009, 1:16pm UTC](https://www.ruby-forum.com/t/storing-c-pointers-in-ruby-hash/167349/3 "2009-05-07T13:16:11Z")

</div>

Rolando A. wrote:

> > I’m been banging my head on the keyboard the whole day trying to  
> > track a bug.

You probably should post more information about what happens when the  
bug hits: eg is it a rb\_bug, and if so, with what message? Can you  
provide a gdb backtrace of the C call stack?

> > The idea is to keep a reference to the ruby counterpart of the Obj-C  
> > object. Right now, I’m using a “global” hash table, defined as this:

…

The code looks ok from a casual look, though I’m not sure INT2FIX is the  
right conversion macro to use. SWIG does this to create a conversion  
macro (SWIG2NUM) for making Ruby hash keys from pointers.

/\* Ruby 1.8 actually assumes the first case. \*/  
#if SIZEOF\_VOIDP == SIZEOF\_LONG

# define SWIG2NUM(v) LONG2NUM((unsigned long)v)

# define NUM2SWIG(x) (unsigned long)NUM2LONG(x)

#elif SIZEOF\_VOIDP == SIZEOF\_LONG\_LONG

# define SWIG2NUM(v) LL2NUM((unsigned long long)v)

# define NUM2SWIG(x) (unsigned long long)NUM2LL(x)

#else

# error sizeof(void\*) is not the same as long or long long

#endif

> > The thing is, that the rb\_obj is crashing the ruby interpreter. If I  
> > try to call any method on it (even inspect) I get a bad access  
> > error. It was working with a ruby 1.8 version, but now that I’ve  
> > ruby 1.9, it refuses to work… Any idea of what I could be doing  
> > wrong here?

If above doesn’t help, what version of 1.8 were you using previously? If  
\< 1.8.7 then you might see if the bug is “object allocation during  
garbage collection”. The size of pointers on Mac OS X mean that when  
they are converted to ruby Numerics, they may be BigNums. These are not  
immediate objects and involve allocation; if you happen to do this  
during GC it’s a mistake. Ruby 1.8.6 and earlier were indulgent to this  
failing, but 1.8.7 and 1.9.1 are not.

You could test this by placing GC.disable at the very start of your  
script and seeing if the crash still happens.

> > Is there a better way to link a ruby object with a c pointer? I need  
> > to get the associated ruby object to a given objc object.

Do you have an alternate hash map implementation available, eg from ObjC  
standard libraries? Can you use this instead to create a straight  
pointer-\>VALUE map? I would try this as using Ruby Hash adds unnecessary  
complexity involved with converting the pointer keys to VALUE, and GC.

Several of the things you appear to be trying to do (have a persistent  
ObjC -\> Ruby object link; forward method calls from ObjC to Ruby) are  
similar to what SWIG provides for C++ and you might find it useful to  
look at the implementation of “object tracking” and  
“directors”/“cross-language polymorphism” there.

The former uses a hash, the latter uses a C++ class which multiply  
inherits from the wrapped C++ class and a simple C++ class called  
“Director” which has the VALUE as member, and forwards method calls to  
rb\_funcall on that VALUE.

hth  
alex

---

<div class="post-metadata">

**Author:** ![Rolando\_A](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/d9b06d/32.png) [@Rolando\_A](https://www.ruby-forum.com/u/Rolando_A)\
**Post date:** [May 7, 2009, 3:22pm UTC](https://www.ruby-forum.com/t/storing-c-pointers-in-ruby-hash/167349/4 "2009-05-07T15:22:20Z")

</div>

On May 7, 2009, at 7:15 AM, Alex F. wrote:

> Rolando A. wrote:
> 
> > > I’m been banging my head on the keyboard the whole day trying to  
> > > track a bug.
> 
> You probably should post more information about what happens when  
> the bug hits: eg is it a rb\_bug, and if so, with what message? Can  
> you provide a gdb backtrace of the C call stack?

Here’s the backtrack when trying to use the Data\_Get\_Struct() macro on  
the object back from the hash table:

#0 0x000a546c in st\_lookup (table=0xdaa29, key=9864,  
value=0xbfffe28c) at /Users/rolando/Documents/GFF/ShinyCocos/ruby/st.c:  
289  
#1 0x0010475e in search\_method (klass=92302960, id=9864, klassp=0x0)  
at vm\_method.c:229  
#2 0x001047a8 in rb\_get\_method\_body (klass=92302960, id=9864,  
idp=0xbfffe334) at vm\_method.c:256  
#3 0x00106ff9 in rb\_call0 (klass=92302960, recv=92302800, mid=9864,  
argc=0, argv=0x0, scope=1, self=6) at vm\_eval.c:205  
#4 0x00106ea7 in rb\_call (klass=92302960, recv=92302800, mid=9864,  
argc=0, argv=0x0, scope=1) at vm\_eval.c:255  
#5 0x001072cf in rb\_funcall (recv=92302800, mid=9864, n=0) at  
vm\_eval.c:427  
#6 0x000d10e2 in -[CocosNode(SC\_Extension) rb\_on\_enter]  
(self=0x5778540, \_cmd=0x1a75dc) at /Users/rolando/Documents/GFF/  
ShinyCocos/Integration/SC\_CocosNode.m:72  
#7 0x00174a11 in -[CocosNode onEnter] (self=0x5778330, \_cmd=0x19ca9f)  
at /Users/rolando/Documents/GFF/ShinyCocos/cocos2d-iphone/cocos2d/  
CocosNode.m:529  
#8 0x000d10ac in -[CocosNode(SC\_Extension) rb\_on\_enter]  
(self=0x5778330, \_cmd=0x1a75dc) at /Users/rolando/Documents/GFF/  
ShinyCocos/Integration/SC\_CocosNode.m:69  
#9 0x00174a11 in -[CocosNode onEnter] (self=0x5775e90, \_cmd=0x19ca9f)  
at /Users/rolando/Documents/GFF/ShinyCocos/cocos2d-iphone/cocos2d/  
CocosNode.m:529  
#10 0x000d10ac in -[CocosNode(SC\_Extension) rb\_on\_enter]  
(self=0x5775e90, \_cmd=0x1a75dc) at /Users/rolando/Documents/GFF/  
ShinyCocos/Integration/SC\_CocosNode.m:69  
#11 0x00174a11 in -[CocosNode onEnter] (self=0x5775e30, \_cmd=0x19ca9f)  
at /Users/rolando/Documents/GFF/ShinyCocos/cocos2d-iphone/cocos2d/  
CocosNode.m:529  
#12 0x000d10ac in -[CocosNode(SC\_Extension) rb\_on\_enter]  
(self=0x5775e30, \_cmd=0x1a75dc) at /Users/rolando/Documents/GFF/  
ShinyCocos/Integration/SC\_CocosNode.m:69  
#13 0x00179386 in -[Director setNextScene] (self=0x1070fd0,  
\_cmd=0x1a7882) at /Users/rolando/Documents/GFF/ShinyCocos/cocos2d-  
iphone/cocos2d/Director.m:649  
#14 0x00177a13 in -[Director mainLoop] (self=0x1070fd0, \_cmd=0x1a76ff)  
at /Users/rolando/Documents/GFF/ShinyCocos/cocos2d-iphone/cocos2d/  
Director.m:185  
#15 0x94505e23 in \_\_NSFireTimer ()  
#16 0x9213cb25 in CFRunLoopRunSpecific ()  
#17 0x9213ccd8 in CFRunLoopRunInMode ()  
#18 0x31566600 in GSEventRunModal ()  
#19 0x315666c5 in GSEventRun ()  
#20 0x30a4eca0 in -[UIApplication \_run] ()  
#21 0x30a5a09c in UIApplicationMain ()  
#22 0x0000200a in main (argc=1, argv=0xbfffeee4) at /Users/rolando/  
Documents/GFF/ShinyCocos/\_DC/main.m:14

> # define SWIG2NUM(v) LL2NUM((unsigned long long)v)
> 
> # define NUM2SWIG(x) (unsigned long long)NUM2LL(x)
> 
> #else
> 
> # error sizeof(void\*) is not the same as long or long long
> 
> #endif

I thought about this. I tried using (ruby) string keys just to make  
sure it wasn’t that sort of problem. Same issue. I even went further  
and removed the hash table, using an instance variable in the objc  
class that will be linked to a ruby class (I wanted to avoid this). It  
crashed in the same way.

> If above doesn’t help, what version of 1.8 were you using  
> previously? If \< 1.8.7 then you might see if the bug is “object  
> allocation during garbage collection”. The size of pointers on Mac  
> OS X mean that when they are converted to ruby Numerics, they may be  
> BigNums. These are not immediate objects and involve allocation; if  
> you happen to do this during GC it’s a mistake. Ruby 1.8.6 and  
> earlier were indulgent to this failing, but 1.8.7 and 1.9.1 are not.

It was 1.8.8: the stable snapshot that’s on the ruby page, which I  
mistakenly confused with a stable snapshot of the 1.9.1 series, I  
think that link is a bit outdated.

> You could test this by placing GC.disable at the very start of your  
> script and seeing if the crash still happens.

I’ll try that.

> Do you have an alternate hash map implementation available, eg from  
> ObjC standard libraries? Can you use this instead to create a  
> straight pointer-\>VALUE map? I would try this as using Ruby Hash  
> adds unnecessary complexity involved with converting the pointer  
> keys to VALUE, and GC.

I’ll try NSDictionary, but as I got the same error using the raw  
pointer… I’ll give it a shot though.

> Several of the things you appear to be trying to do (have a  
> persistent ObjC -\> Ruby object link; forward method calls from ObjC  
> to Ruby) are similar to what SWIG provides for C++ and you might  
> find it useful to look at the implementation of “object tracking”  
> and “directors”/“cross-language polymorphism” there.
> 
> The former uses a hash, the latter uses a C++ class which multiply  
> inherits from the wrapped C++ class and a simple C++ class called  
> “Director” which has the VALUE as member, and forwards method calls  
> to rb\_funcall on that VALUE.

thanks! I’ll take a look at that code.

> hth  
> alex

regards,

---

<div class="post-metadata">

**Author:** ![Rolando\_A](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/d9b06d/32.png) [@Rolando\_A](https://www.ruby-forum.com/u/Rolando_A)\
**Post date:** [May 7, 2009, 8:15pm UTC](https://www.ruby-forum.com/t/storing-c-pointers-in-ruby-hash/167349/5 "2009-05-07T20:15:03Z")

</div>

No luck yet with this (still banging my head with the keyboard).  
After looking at swig source code and reading this:

\<[SWIG / Bugs / #939 [ruby] generated tracking code errors with Ruby 1.8.7 / 1.9](http://sourceforge.net/tracker/index.php?func=detail&aid=2034216&group_id=1645&atid=101645)

> 

I realized that using a ruby hash was a bad idea. Although I had  
tested using a simple pointer, I changed the approach using a  
NSDictionary. I also added some debug output, and the VALUE I get back  
from the hash is the same, but If I call any function on that object,  
I get a crash:

#0 0x000a56c6 in st\_lookup (table=0x0, key=760, value=0xbfffe20c) at /  
Users/rolando/Documents/GFF/ShinyCocos/ruby/st.c:286  
#1 0x00105702 in search\_method (klass=92295000, id=760, klassp=0x0)  
at vm\_method.c:229  
#2 0x0010574c in rb\_get\_method\_body (klass=92295000, id=760,  
idp=0xbfffe2b4) at vm\_method.c:256  
#3 0x00107f9d in rb\_call0 (klass=92295000, recv=92302820, mid=760,  
argc=0, argv=0x0, scope=1, self=6) at vm\_eval.c:205  
#4 0x00107e4b in rb\_call (klass=92295000, recv=92302820, mid=760,  
argc=0, argv=0x0, scope=1) at vm\_eval.c:255  
#5 0x00108273 in rb\_funcall (recv=92302820, mid=760, n=0) at  
vm\_eval.c:427  
#6 0x000d1811 in sc\_ruby\_instance\_for (hash=0x10622e0,  
obj1=0x5778810) at SC\_common.h:86

… should I fill a bug report? :-S  
I’ll try to put a simple demo file to simplify the example (although  
the latest code that reflects this is in  
\<[GitHub - rolandoam/shinycocos: ruby bindings for cocos2d-iphone (a.k.a.: i want to program my iphone game in ruby)](http://github.com/funkaster/shinycocos/tree/master)

> , you might need iPhone SDK to test it though).

Thanks for any tip!

---

<div class="post-metadata">

**Author:** ![Rolando\_A](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/d9b06d/32.png) [@Rolando\_A](https://www.ruby-forum.com/u/Rolando_A)\
**Post date:** [May 7, 2009, 4:09pm UTC](https://www.ruby-forum.com/t/storing-c-pointers-in-ruby-hash/167349/6 "2009-05-07T16:09:48Z")

</div>

On May 7, 2009, at 7:15 AM, Alex F. wrote:

> If above doesn’t help, what version of 1.8 were you using  
> previously? If \< 1.8.7 then you might see if the bug is “object  
> allocation during garbage collection”. The size of pointers on Mac  
> OS X mean that when they are converted to ruby Numerics, they may be  
> BigNums. These are not immediate objects and involve allocation; if  
> you happen to do this during GC it’s a mistake. Ruby 1.8.6 and  
> earlier were indulgent to this failing, but 1.8.7 and 1.9.1 are not.
> 
> You could test this by placing GC.disable at the very start of your  
> script and seeing if the crash still happens.

disabling the GC, lend me to rb\_bug:

:2: [BUG] Segmentation fault  
ruby 1.9.1p0 (2009-05-04 revision 23343) [i386-darwin9.6.0]

#0 0x0010dc54 in control\_frame\_dump (th=0x10248e0, cfp=0xfaefd0) at /  
Users/rolando/Documents/GFF/ShinyCocos/ruby/vm\_dump.c:108  
#1 0x0010e016 in rb\_vmdebug\_stack\_dump\_raw (th=0x10248e0,  
cfp=0xfaefd0) at /Users/rolando/Documents/GFF/ShinyCocos/ruby/  
vm\_dump.c:176  
#2 0x0010ea2e in rb\_vm\_bugreport () at /Users/rolando/Documents/GFF/  
ShinyCocos/ruby/vm\_dump.c:575  
#3 0x00024d05 in report\_bug (file=0x640014 “\034\001”, line=2,  
fmt=0x19b143 “Segmentation fault”, args=0x7e8cd4 “\213E\b\211”) at /  
Users/rolando/Documents/GFF/ShinyCocos/ruby/error.c:215  
#4 0x00024d6f in rb\_bug (fmt=0x19b143 “Segmentation fault”) at /Users/  
rolando/Documents/GFF/ShinyCocos/ruby/error.c:230  
#5 0x0009d7bc in sigsegv (sig=11, info=0x7e8fa0, ctx=0x7e8fe0) at /  
Users/rolando/Documents/GFF/ShinyCocos/ruby/signal.c:605  
#6  
#7 0x000a546c in st\_lookup (table=0xdaa29, key=9864,  
value=0xbfffe28c) at /Users/rolando/Documents/GFF/ShinyCocos/ruby/st.c:  
289  
#8 0x0010475e in search\_method (klass=92302780, id=9864, klassp=0x0)  
at vm\_method.c:229  
#9 0x001047a8 in rb\_get\_method\_body (klass=92302780, id=9864,  
idp=0xbfffe334) at vm\_method.c:256  
#10 0x00106ff9 in rb\_call0 (klass=92302780, recv=92302620, mid=9864,  
argc=0, argv=0x0, scope=1, self=6) at vm\_eval.c:205  
#11 0x00106ea7 in rb\_call (klass=92302780, recv=92302620, mid=9864,  
argc=0, argv=0x0, scope=1) at vm\_eval.c:255  
#12 0x001072cf in rb\_funcall (recv=92302620, mid=9864, n=0) at  
vm\_eval.c:427  
#13 0x000d10e2 in -[CocosNode(SC\_Extension) rb\_on\_enter]  
(self=0x5778580, \_cmd=0x1a75dc) at /Users/rolando/Documents/GFF/  
ShinyCocos/Integration/SC\_CocosNode.m:72  
#14 0x00174a11 in -[CocosNode onEnter] (self=0x5778370, \_cmd=0x19ca9f)  
at /Users/rolando/Documents/GFF/ShinyCocos/cocos2d-iphone/cocos2d/  
CocosNode.m:529  
#15 0x000d10ac in -[CocosNode(SC\_Extension) rb\_on\_enter]  
(self=0x5778370, \_cmd=0x1a75dc) at /Users/rolando/Documents/GFF/  
ShinyCocos/Integration/SC\_CocosNode.m:69  
#16 0x00174a11 in -[CocosNode onEnter] (self=0x5775ed0, \_cmd=0x19ca9f)  
at /Users/rolando/Documents/GFF/ShinyCocos/cocos2d-iphone/cocos2d/  
CocosNode.m:529  
#17 0x000d10ac in -[CocosNode(SC\_Extension) rb\_on\_enter]  
(self=0x5775ed0, \_cmd=0x1a75dc) at /Users/rolando/Documents/GFF/  
ShinyCocos/Integration/SC\_CocosNode.m:69  
#18 0x00174a11 in -[CocosNode onEnter] (self=0x5775e70, \_cmd=0x19ca9f)  
at /Users/rolando/Documents/GFF/ShinyCocos/cocos2d-iphone/cocos2d/  
CocosNode.m:529  
#19 0x000d10ac in -[CocosNode(SC\_Extension) rb\_on\_enter]  
(self=0x5775e70, \_cmd=0x1a75dc) at /Users/rolando/Documents/GFF/  
ShinyCocos/Integration/SC\_CocosNode.m:69  
#20 0x00179386 in -[Director setNextScene] (self=0x1070fd0,  
\_cmd=0x1a7882) at /Users/rolando/Documents/GFF/ShinyCocos/cocos2d-  
iphone/cocos2d/Director.m:649  
#21 0x00177a13 in -[Director mainLoop] (self=0x1070fd0, \_cmd=0x1a76ff)  
at /Users/rolando/Documents/GFF/ShinyCocos/cocos2d-iphone/cocos2d/  
Director.m:185  
#22 0x94505e23 in \_\_NSFireTimer ()  
#23 0x9213cb25 in CFRunLoopRunSpecific ()  
#24 0x9213ccd8 in CFRunLoopRunInMode ()  
#25 0x31566600 in GSEventRunModal ()  
#26 0x315666c5 in GSEventRun ()  
#27 0x30a4eca0 in -[UIApplication \_run] ()  
#28 0x30a5a09c in UIApplicationMain ()  
#29 0x0000200a in main (argc=1, argv=0xbfffeee4) at /Users/rolando/  
Documents/GFF/ShinyCocos/\_DC/main.m:14

Will check a few things and try again.  
Btw, you were totally right, the way swig tracks objects is almost the  
same thing I’m trying to do. I’ll take a closer look to the code.

cheers,
