* ext/dl/cfunc.c (dlcfunc_mark), ext/dl/cptr.c (dlptr_mark):

workaround to mark wrapped object.  this is not a true fix,
  because [Bug #4929] is caused by the interface design of DL.

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@32712 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
nobu 2011-07-27 17:15:09 +00:00
parent 5c815b733d
commit 9f3914aba6
5 changed files with 68 additions and 27 deletions

View File

@ -1,3 +1,9 @@
Thu Jul 28 02:15:04 2011 Nobuyoshi Nakada <nobu@ruby-lang.org>
* ext/dl/cfunc.c (dlcfunc_mark), ext/dl/cptr.c (dlptr_mark):
workaround to mark wrapped object. this is not a true fix,
because [Bug #4929] is caused by the interface design of DL.
Thu Jul 28 00:28:15 2011 NARUSE, Yui <naruse@ruby-lang.org> Thu Jul 28 00:28:15 2011 NARUSE, Yui <naruse@ruby-lang.org>
* test/fileutils/test_fileutils.rb: add OpenBSD case. * test/fileutils/test_fileutils.rb: add OpenBSD case.

View File

@ -41,6 +41,14 @@ rb_dl_set_win32_last_error(VALUE self, VALUE val)
} }
#endif #endif
static void
dlcfunc_mark(void *ptr)
{
struct cfunc_data *data = ptr;
if (data->wrap) {
rb_gc_mark(data->wrap);
}
}
static void static void
dlcfunc_free(void *ptr) dlcfunc_free(void *ptr)
@ -68,7 +76,7 @@ dlcfunc_memsize(const void *ptr)
const rb_data_type_t dlcfunc_data_type = { const rb_data_type_t dlcfunc_data_type = {
"dl/cfunc", "dl/cfunc",
{0, dlcfunc_free, dlcfunc_memsize,}, {dlcfunc_mark, dlcfunc_free, dlcfunc_memsize,},
}; };
VALUE VALUE
@ -143,14 +151,15 @@ rb_dlcfunc_kind_p(VALUE func)
static VALUE static VALUE
rb_dlcfunc_initialize(int argc, VALUE argv[], VALUE self) rb_dlcfunc_initialize(int argc, VALUE argv[], VALUE self)
{ {
VALUE addr, name, type, calltype; VALUE addr, name, type, calltype, addrnum;
struct cfunc_data *data; struct cfunc_data *data;
void *saddr; void *saddr;
const char *sname; const char *sname;
rb_scan_args(argc, argv, "13", &addr, &type, &name, &calltype); rb_scan_args(argc, argv, "13", &addr, &type, &name, &calltype);
saddr = (void*)(NUM2PTR(rb_Integer(addr))); addrnum = rb_Integer(addr);
saddr = (void*)(NUM2PTR(addrnum));
sname = NIL_P(name) ? NULL : StringValuePtr(name); sname = NIL_P(name) ? NULL : StringValuePtr(name);
TypedData_Get_Struct(self, struct cfunc_data, &dlcfunc_data_type, data); TypedData_Get_Struct(self, struct cfunc_data, &dlcfunc_data_type, data);
@ -159,6 +168,7 @@ rb_dlcfunc_initialize(int argc, VALUE argv[], VALUE self)
data->name = sname ? strdup(sname) : 0; data->name = sname ? strdup(sname) : 0;
data->type = NIL_P(type) ? DLTYPE_VOID : NUM2INT(type); data->type = NIL_P(type) ? DLTYPE_VOID : NUM2INT(type);
data->calltype = NIL_P(calltype) ? CFUNC_CDECL : SYM2ID(calltype); data->calltype = NIL_P(calltype) ? CFUNC_CDECL : SYM2ID(calltype);
data->wrap = (addrnum == addr) ? 0 : addr;
return Qnil; return Qnil;
} }

View File

@ -10,19 +10,36 @@
VALUE rb_cDLCPtr; VALUE rb_cDLCPtr;
static inline freefunc_t static inline freefunc_t
get_freefunc(VALUE func) get_freefunc(VALUE func, volatile VALUE *wrap)
{ {
VALUE addrnum;
if (NIL_P(func)) { if (NIL_P(func)) {
*wrap = 0;
return NULL; return NULL;
} }
if (rb_dlcfunc_kind_p(func)) { if (rb_dlcfunc_kind_p(func)) {
*wrap = func;
return (freefunc_t)(VALUE)RCFUNC_DATA(func)->ptr; return (freefunc_t)(VALUE)RCFUNC_DATA(func)->ptr;
} }
return (freefunc_t)(VALUE)NUM2PTR(rb_Integer(func)); addrnum = rb_Integer(func);
*wrap = (addrnum != func) ? func : 0;
return (freefunc_t)(VALUE)NUM2PTR(addrnum);
} }
static ID id_to_ptr; static ID id_to_ptr;
static void
dlptr_mark(void *ptr)
{
struct ptr_data *data = ptr;
if (data->wrap[0]) {
rb_gc_mark(data->wrap[0]);
}
if (data->wrap[1]) {
rb_gc_mark(data->wrap[1]);
}
}
static void static void
dlptr_free(void *ptr) dlptr_free(void *ptr)
{ {
@ -43,7 +60,7 @@ dlptr_memsize(const void *ptr)
static const rb_data_type_t dlptr_data_type = { static const rb_data_type_t dlptr_data_type = {
"dl/ptr", "dl/ptr",
{0, dlptr_free, dlptr_memsize,}, {dlptr_mark, dlptr_free, dlptr_memsize,},
}; };
void void
@ -135,27 +152,22 @@ rb_dlptr_s_allocate(VALUE klass)
static VALUE static VALUE
rb_dlptr_initialize(int argc, VALUE argv[], VALUE self) rb_dlptr_initialize(int argc, VALUE argv[], VALUE self)
{ {
VALUE ptr, sym, size; VALUE ptr, sym, size, wrap = 0, funcwrap = 0;
struct ptr_data *data; struct ptr_data *data;
void *p = NULL; void *p = NULL;
freefunc_t f = NULL; freefunc_t f = NULL;
long s = 0; long s = 0;
switch (rb_scan_args(argc, argv, "12", &ptr, &size, &sym)) { if (rb_scan_args(argc, argv, "12", &ptr, &size, &sym) >= 1) {
case 1: VALUE addrnum = rb_Integer(ptr);
p = (void*)(NUM2PTR(rb_Integer(ptr))); if (addrnum != ptr) wrap = ptr;
break; p = NUM2PTR(addrnum);
case 2: }
p = (void*)(NUM2PTR(rb_Integer(ptr))); if (argc >= 2) {
s = NUM2LONG(size); s = NUM2LONG(size);
break; }
case 3: if (argc >= 3) {
p = (void*)(NUM2PTR(rb_Integer(ptr))); f = get_freefunc(sym, &funcwrap);
s = NUM2LONG(size);
f = get_freefunc(sym);
break;
default:
rb_bug("rb_dlptr_initialize");
} }
if (p) { if (p) {
@ -164,6 +176,8 @@ rb_dlptr_initialize(int argc, VALUE argv[], VALUE self)
/* Free previous memory. Use of inappropriate initialize may cause SEGV. */ /* Free previous memory. Use of inappropriate initialize may cause SEGV. */
(*(data->free))(data->ptr); (*(data->free))(data->ptr);
} }
data->wrap[0] = wrap;
data->wrap[1] = funcwrap;
data->ptr = p; data->ptr = p;
data->size = s; data->size = s;
data->free = f; data->free = f;
@ -185,7 +199,7 @@ rb_dlptr_initialize(int argc, VALUE argv[], VALUE self)
static VALUE static VALUE
rb_dlptr_s_malloc(int argc, VALUE argv[], VALUE klass) rb_dlptr_s_malloc(int argc, VALUE argv[], VALUE klass)
{ {
VALUE size, sym, obj; VALUE size, sym, obj, wrap = 0;
long s; long s;
freefunc_t f; freefunc_t f;
@ -196,13 +210,14 @@ rb_dlptr_s_malloc(int argc, VALUE argv[], VALUE klass)
break; break;
case 2: case 2:
s = NUM2LONG(size); s = NUM2LONG(size);
f = get_freefunc(sym); f = get_freefunc(sym, &wrap);
break; break;
default: default:
rb_bug("rb_dlptr_s_malloc"); rb_bug("rb_dlptr_s_malloc");
} }
obj = rb_dlptr_malloc(s,f); obj = rb_dlptr_malloc(s,f);
if (wrap) RPTR_DATA(obj)->wrap[1] = wrap;
return obj; return obj;
} }
@ -289,7 +304,7 @@ rb_dlptr_free_set(VALUE self, VALUE val)
struct ptr_data *data; struct ptr_data *data;
TypedData_Get_Struct(self, struct ptr_data, &dlptr_data_type, data); TypedData_Get_Struct(self, struct ptr_data, &dlptr_data_type, data);
data->free = get_freefunc(val); data->free = get_freefunc(val, &data->wrap[1]);
return Qnil; return Qnil;
} }
@ -582,7 +597,7 @@ rb_dlptr_size_get(VALUE self)
static VALUE static VALUE
rb_dlptr_s_to_ptr(VALUE self, VALUE val) rb_dlptr_s_to_ptr(VALUE self, VALUE val)
{ {
VALUE ptr; VALUE ptr, wrap = val;
if (RTEST(rb_obj_is_kind_of(val, rb_cIO))){ if (RTEST(rb_obj_is_kind_of(val, rb_cIO))){
rb_io_t *fptr; rb_io_t *fptr;
@ -599,16 +614,19 @@ rb_dlptr_s_to_ptr(VALUE self, VALUE val)
VALUE vptr = rb_funcall(val, id_to_ptr, 0); VALUE vptr = rb_funcall(val, id_to_ptr, 0);
if (rb_obj_is_kind_of(vptr, rb_cDLCPtr)){ if (rb_obj_is_kind_of(vptr, rb_cDLCPtr)){
ptr = vptr; ptr = vptr;
wrap = 0;
} }
else{ else{
rb_raise(rb_eDLError, "to_ptr should return a CPtr object"); rb_raise(rb_eDLError, "to_ptr should return a CPtr object");
} }
} }
else{ else{
ptr = rb_dlptr_new(NUM2PTR(rb_Integer(val)), 0, NULL); VALUE num = rb_Integer(val);
if (num != val) wrap = 0;
ptr = rb_dlptr_new(NUM2PTR(num), 0, NULL);
} }
OBJ_INFECT(ptr, val); OBJ_INFECT(ptr, val);
rb_iv_set(ptr, "wrapping", val); if (wrap) RPTR_DATA(ptr)->wrap[0] = wrap;
return ptr; return ptr;
} }

View File

@ -199,6 +199,7 @@ struct cfunc_data {
char *name; char *name;
int type; int type;
ID calltype; ID calltype;
VALUE wrap;
}; };
extern ID rbdl_id_cdecl; extern ID rbdl_id_cdecl;
extern ID rbdl_id_stdcall; extern ID rbdl_id_stdcall;
@ -209,6 +210,7 @@ struct ptr_data {
void *ptr; void *ptr;
long size; long size;
freefunc_t free; freefunc_t free;
VALUE wrap[2];
}; };
#define RDL_HANDLE(obj) ((struct dl_handle *)(DATA_PTR(obj))) #define RDL_HANDLE(obj) ((struct dl_handle *)(DATA_PTR(obj)))

View File

@ -95,6 +95,11 @@ module DL
buff = "9341" buff = "9341"
qsort.call(buff, buff.size, 1, cb) qsort.call(buff, buff.size, 1, cb)
assert_equal("1349", buff) assert_equal("1349", buff)
bug4929 = '[ruby-core:37395]'
buff = "9341"
EnvUtil.under_gc_stress {qsort.call(buff, buff.size, 1, cb)}
assert_equal("1349", buff, bug4929)
end end
def test_qsort2() def test_qsort2()