まつもとさん、回答ありがとうございました。

変数の初期化あたりも見直したのですが、どうもよくわかりませんでした。

ようやく問題になっている部分を追い込めたのは以下のようなコードでした。


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