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

From: Kouhei Sutou <kou@...>
Date: 2015-08-09 03:28:51 UTC
List: ruby-list #50215
須藤です。

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