From: Kouhei Sutou Date: 2015-08-09T12:28:51+09:00 Subject: [ruby-list:50215] Re: 拡張ライブラリでのSEGV 須藤です。 In "[ruby-list:50214] 拡張ライブラリでのSEGV" on Sun, 9 Aug 2015 11:02:53 +0900, Hidetoshi Saito wrote: > static VALUE clsdebug_alloc(VALUE klass) > { > struct debugobj *ptr = ALLOC(struct debugobj); ここに ptr->ary = Qnil; を入れるといいと思います。 > return Data_Wrap_Struct(klass, clsdebug_mark, -1, ptr); > } clsdebug_alloc()が呼ばれた後、 > static VALUE > rb_clsdebug_init(VALUE self) > { > char *p_str; > char str[]="abcdefghijklmns"; > int i,len; > > struct debugobj *ptr; > Data_Get_Struct(self, struct debugobj, ptr); > > p_str=str; > len = strlen(p_str); ここまでの間にGCが走るとptr->aryの中身がどうなっているかわか らないのでrb_gc_mark(ptr->ary)したときに落ちる可能性がありま す。 > ptr->ary = rb_ary_new(); ところで、ALLOC()した領域をxfree()した方がいいんじゃないかなぁ と思いました。 私が拡張ライブラリーを書くときはXXX_alloc()ではALLOC()せずに、 NULLをData_Wrap_Struct()するだけにして、initializeに対応する Cの関数の方でALLOC()(を使ったり、別の方法を使ったりしてメモ リーを確保)しています。(見たらそうしていました。) ということで、私ならこんな感じにします。 #include #include #include #include struct debugobj{ VALUE ary; }; static void clsdebug_mark(struct debugobj *ptr) { rb_gc_mark(ptr->ary); } static void clsdebug_free(struct debugobj *ptr) { xfree(ptr); } static VALUE clsdebug_alloc(VALUE klass) { return Data_Wrap_Struct(klass, clsdebug_mark, clsdebug_free, NULL); } static VALUE rb_clsdebug_init(VALUE self) { char *p_str; char str[]="abcdefghijklmns"; int i,len; struct debugobj *ptr = NULL; ptr = ALLOC(struct debugobj); ptr->ary = Qnil; DATA_PTR(self) = ptr; p_str=str; len = strlen(p_str); ptr->ary = rb_ary_new(); for(i=0;iary,v); } return Qnil; } static VALUE rb_clsdebug_ary(VALUE self) { struct debugobj *ptr; Data_Get_Struct(self, struct debugobj, ptr); volatile VALUE v = ptr->ary; return v; } void Init_libdebug(void) { VALUE libDebug; VALUE clsdebug; libDebug = rb_define_module("LibDebug"); clsdebug = rb_define_class_under(libDebug, "Clsdebug", rb_cObject); rb_define_alloc_func(clsdebug, clsdebug_alloc); rb_define_method(clsdebug, "initialize", RUBY_METHOD_FUNC(rb_clsdebug_init), 0); rb_define_method(clsdebug, "to_a", RUBY_METHOD_FUNC(rb_clsdebug_ary), 0); }