苦節一ヶ月、ようやく解決しました。

Cのライブラリが返してくるハンドル(ようはポインタ)を

return (VALUE)h

とかで返してRubyのほうで振り分けてたのですが、これはやはりいかんと思い、
構造体のラッパを作って、Data_Make_Structでラップして返すように全部書き直したらなおりました。

よく今まで動いてたものです。

inaba

Inaba,Touru wrote:
> inabaです。
>
> 一箇所自分の間違いをみつけました。
> 前はAttrGetNextは3個の値を返してたのが仕様変更で今は2個になってたのにコードを修正してませんでした。
>
> したがって、正しくは、ary = rb_ary_new2(2)にして、 rb_ary_push(ary, Qnil) を3回連続してるのを
> 2回にしました。しかし、これをやってもあいかわらず落ちてます。
>
> Inaba,Touru wrote:
>> まつもとさん、回答ありがとうございました。
>>
>> 変数の初期化あたりも見直したのですが、どうもよくわかりませんでした。
>>
>> ようやく問題になっている部分を追い込めたのは以下のようなコードでした。
>>
>>
>> static VALUE AttrGetNext(VALUE obj0, VALUE db, VALUE obj,
>>                             VALUE coverindex, VALUE key)
>> {
>>    VALUE ary, ary2;
>>    char *in_key;
>>    char *out_key;
>>    AttrValueT value;
>>    AttrValueT *valuep;
>>    int i;
>>    VALUE v;
>>
>>    assert((void *)db != NULL);
>>    Check_Type(coverindex, T_FIXNUM);
>>
>>    ary = rb_ary_new2(3);
>>
>>    if (NIL_P(key))
>>      in_key = NULL;
>>    else {
>>      Check_Type(key, T_STRING);
>>      in_key = RSTRING_PTR(key);
>>    }
>>    // 以下がRubyから呼びたいCのライブラリ関数
>>    out_key = (char *)AttrGetNext((dbT)db, NIL_P(obj) ? NULL : (dbObjT)obj,
>>                                           FIX2INT(coverindex), in_key, &value);
>>
>>    if (out_key == NULL) {
>>      rb_ary_push(ary, Qnil);
>>      rb_ary_push(ary, Qnil);
>>      rb_ary_push(ary, Qnil);
>>    } else {
>>      v = rb_class_new_instance(0, NULL, cAttrValue);
>>      if (Qnil == v) {
>>        fprintf(stderr, "failed rb_class_new_instance(0, NULL, cAttrValue)\n");
>>        exit(1);
>>      }
>>      Data_Get_Struct(v, AttrValueT, valuep);
>>
>>      rb_ary_push(ary, rb_str_new2(out_key));
>>      valuep->type = value.type;
>>      switch(value.type) {
>>      case ATTR_INT64:
>>        valuep->u.i64value = value.u.i64value;
>>        break;
>>      case ATTR_INT:
>>        valuep->u.ivalue = value.u.ivalue;
>>        break;
>>      case ATTR_FLOAT:
>>        valuep->u.fvalue = value.u.fvalue;
>>        break;
>>      case ATTR_DOUBLE:
>>        valuep->u.dvalue = value.u.dvalue;
>>        break;
>>      case ATTR_STRING:
>>        valuep->u.svalue = value.u.svalue;
>>        break;
>>      case ATTR_MEMBLK:
>>        valuep->u.mvalue.size = value.u.mvalue.size;
>>        valuep->u.mvalue.data = value.u.mvalue.data;
>>        for (i=0; i<value.u.mvalue.size; i++)
>>          valuep->u.mvalue.data[i] = value.u.mvalue.data[i];
>>        break;
>>      default:
>>        fprintf(stderr, "AttrNext: unknown type %x\n", value.type);
>>        v = Qnil;
>>        break;
>>      }
>>      rb_ary_push(ary, v);
>>    }
>>    return ary;
>> }
>>
>> そしてrb_class_new_instanceで生成しているものの定義は以下のようなものです。
>>
>>
>> /*-------------------------- AttrValueT class --------------------------*/
>> static VALUE
>> AttrValue_s_allocate(VALUE class)
>> {
>>    AttrValueT* p;
>>
>>    return Data_Make_Struct(class, AttrValueT, 0, 0, p);
>> }
>>
>> static VALUE
>> AttrValue_initialize(VALUE obj)
>> {
>>    AttrValueT *av;
>>
>>    Data_Get_Struct(obj, AttrValueT, av);
>>    if (av == NULL) return Qnil;
>>    else return obj;
>> }
>>
>> (他のメソッド定義は略)
>>
>> 他でも似たようなクラスを同じように使っている部分は多いので、AttrGetNext で
>> 三つの値を返すためにrb_ary_new2(3)で作った配列に積んでいるあたりが怪しいと見ているのですが
>> いかがでしょうか?
>>
>> inaba
>>
>> Yukihiro Matsumoto wrote:
>>> まつもと ゆきひろです
>>>
>>> 無視しているわけではないということを示すだけの返事です。
>>>
>>> rb_gc_mark()で落ちる原因はほぼ間違いなくどこかの変数の初期化
>>> 漏れですが、それ以上のことは言えません。ライブラリをロードし
>>> たことで落ちなくなるのは、初期化前にGCが呼ばれていたものが、
>>> ライブラリのロードによってGCのタイミングがずれるからでしょう。
>>>
>>> これ以上はソースがないことにはなんとも。
>>>
>>> In message "Re: [ruby-ext:02341] Re: [BUG] rb_gc_mark()"
>>>      on Wed, 21 Nov 2012 16:37:15 +0900, "Inaba,Touru" <inaba / lake.dti.ne.jp> writes:
>>> |
>>> |一週間ほど苦闘してきましたが、あいかわらずわかりません。
>>> |Data_Make_Structを使っている付近は随分チェックしたのですが。
>>> |いろいろvolatileを入れたりしてもだめ。
>>> |
>>> |一応あるところで rb_class_new_instance しているところで落ちているところまではわかったのですが、
>>> |その原因のほうはさっぱり。
>>> |
>>> |さらにわけわからんのは、
>>> |
>>> |require "optparse"
>>> |
>>> |すると落ちなくなるという... optparseは全然使ってなくてもです。
>>> |
>>> |inaba
>>>
>>>
>>
>>
>>
>
>
>