[ruby-list:50216] Re: 拡張ライブラリでのSEGV

From: Hidetoshi Saito <hidetoshi.saito@...>
Date: 2015-08-09 03:58:35 UTC
List: ruby-list #50216
須藤様

適切なご指摘ありがとうございます。
合わせて、ALLOC とxfreeのご指導もありがとうございます。
改編後のソースは正しく動作いたしました。

大変助かりました。

斎藤


===============================
斎藤 秀俊  Hidetoshi Saito
email  : hidetoshi.saito@gmail.com
===============================


2015年8月9日 12:28 Kouhei Sutou <kou@cozmixng.org>:
> 須藤です。
>
> In <CALFKQwF_ZW65b0iQU_FGHcUgxZQO0a99WbK3sNwaHQiB-nUSuw@mail.gmail.com>
>   "[ruby-list:50214] 拡張ライブラリでのSEGV" on Sun, 9 Aug 2015 11:02:53 +0900,
>   Hidetoshi Saito <hidetoshi.saito@gmail.com> 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 <ruby.h>
> #include <stdio.h>
> #include <stdlib.h>
> #include <string.h>
>
> 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;i<len;i++)
>   {
>     volatile VALUE v = rb_str_new(p_str+i,1);
>     rb_ary_push(ptr->ary,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);
>
> }

In This Thread