[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);
}