storing c pointers in ruby hash

Discussion in 'Ruby' started by Rolando Abarca, May 6, 2009.

  1. 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: http://github.com/funkaster/shinycocos/tree/master)
    Rolando Abarca, May 6, 2009
    #1
    1. Advertising

  2. 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 Abarca wrote:

    > 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: 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,
    --
    Rolando Abarca M.
    Rolando Abarca, May 6, 2009
    #2
    1. Advertising

  3. Rolando Abarca

    Alex Fenton Guest

    Rolando Abarca 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
    Alex Fenton, May 7, 2009
    #3
  4. On May 7, 2009, at 7:15 AM, Alex Fenton wrote:

    > Rolando Abarca 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

    > 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


    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,
    --
    Rolando Abarca M.
    Rolando Abarca, May 7, 2009
    #4
  5. On May 7, 2009, at 7:15 AM, Alex Fenton 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 <signal handler called>
    #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,
    --
    Rolando Abarca M.
    Rolando Abarca, May 7, 2009
    #5
  6. No luck yet with this (still banging my head with the keyboard).
    After looking at swig source code and reading this:

    <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 <http://github.com/funkaster/shinycocos/tree/master
    >, you might need iPhone SDK to test it though).


    Thanks for any tip!
    --
    Rolando Abarca M.
    Rolando Abarca, May 7, 2009
    #6
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. toton
    Replies:
    11
    Views:
    707
    toton
    Oct 13, 2006
  2. cerr

    pointers, pointers, pointers...

    cerr, Apr 7, 2011, in forum: C Programming
    Replies:
    12
    Views:
    672
  3. rp
    Replies:
    1
    Views:
    516
    red floyd
    Nov 10, 2011
  4. Srijayanth Sridhar
    Replies:
    19
    Views:
    612
    David A. Black
    Jul 2, 2008
  5. Colvin
    Replies:
    3
    Views:
    168
    Colvin
    Dec 30, 2003
Loading...

Share This Page