From 9f3914aba6fe3df5a1c4382b655fb0a7df0cdbfa Mon Sep 17 00:00:00 2001 From: nobu Date: Wed, 27 Jul 2011 17:15:09 +0000 Subject: [PATCH] * 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 --- ChangeLog | 6 ++++ ext/dl/cfunc.c | 16 +++++++++-- ext/dl/cptr.c | 66 ++++++++++++++++++++++++++++---------------- ext/dl/dl.h | 2 ++ test/dl/test_func.rb | 5 ++++ 5 files changed, 68 insertions(+), 27 deletions(-) diff --git a/ChangeLog b/ChangeLog index e203e7b18a..06bb06d18a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +Thu Jul 28 02:15:04 2011 Nobuyoshi Nakada + + * 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 * test/fileutils/test_fileutils.rb: add OpenBSD case. diff --git a/ext/dl/cfunc.c b/ext/dl/cfunc.c index a050ab04b3..f076c6f432 100644 --- a/ext/dl/cfunc.c +++ b/ext/dl/cfunc.c @@ -41,6 +41,14 @@ rb_dl_set_win32_last_error(VALUE self, VALUE val) } #endif +static void +dlcfunc_mark(void *ptr) +{ + struct cfunc_data *data = ptr; + if (data->wrap) { + rb_gc_mark(data->wrap); + } +} static void dlcfunc_free(void *ptr) @@ -68,7 +76,7 @@ dlcfunc_memsize(const void *ptr) const rb_data_type_t dlcfunc_data_type = { "dl/cfunc", - {0, dlcfunc_free, dlcfunc_memsize,}, + {dlcfunc_mark, dlcfunc_free, dlcfunc_memsize,}, }; VALUE @@ -143,14 +151,15 @@ rb_dlcfunc_kind_p(VALUE func) static VALUE rb_dlcfunc_initialize(int argc, VALUE argv[], VALUE self) { - VALUE addr, name, type, calltype; + VALUE addr, name, type, calltype, addrnum; struct cfunc_data *data; void *saddr; const char *sname; 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); 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->type = NIL_P(type) ? DLTYPE_VOID : NUM2INT(type); data->calltype = NIL_P(calltype) ? CFUNC_CDECL : SYM2ID(calltype); + data->wrap = (addrnum == addr) ? 0 : addr; return Qnil; } diff --git a/ext/dl/cptr.c b/ext/dl/cptr.c index 68c18ec32c..c2fb60540e 100644 --- a/ext/dl/cptr.c +++ b/ext/dl/cptr.c @@ -10,19 +10,36 @@ VALUE rb_cDLCPtr; static inline freefunc_t -get_freefunc(VALUE func) +get_freefunc(VALUE func, volatile VALUE *wrap) { + VALUE addrnum; if (NIL_P(func)) { + *wrap = 0; return NULL; } if (rb_dlcfunc_kind_p(func)) { + *wrap = func; 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 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 dlptr_free(void *ptr) { @@ -43,7 +60,7 @@ dlptr_memsize(const void *ptr) static const rb_data_type_t dlptr_data_type = { "dl/ptr", - {0, dlptr_free, dlptr_memsize,}, + {dlptr_mark, dlptr_free, dlptr_memsize,}, }; void @@ -135,27 +152,22 @@ rb_dlptr_s_allocate(VALUE klass) static VALUE 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; void *p = NULL; freefunc_t f = NULL; long s = 0; - switch (rb_scan_args(argc, argv, "12", &ptr, &size, &sym)) { - case 1: - p = (void*)(NUM2PTR(rb_Integer(ptr))); - break; - case 2: - p = (void*)(NUM2PTR(rb_Integer(ptr))); + if (rb_scan_args(argc, argv, "12", &ptr, &size, &sym) >= 1) { + VALUE addrnum = rb_Integer(ptr); + if (addrnum != ptr) wrap = ptr; + p = NUM2PTR(addrnum); + } + if (argc >= 2) { s = NUM2LONG(size); - break; - case 3: - p = (void*)(NUM2PTR(rb_Integer(ptr))); - s = NUM2LONG(size); - f = get_freefunc(sym); - break; - default: - rb_bug("rb_dlptr_initialize"); + } + if (argc >= 3) { + f = get_freefunc(sym, &funcwrap); } 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. */ (*(data->free))(data->ptr); } + data->wrap[0] = wrap; + data->wrap[1] = funcwrap; data->ptr = p; data->size = s; data->free = f; @@ -185,7 +199,7 @@ rb_dlptr_initialize(int argc, VALUE argv[], VALUE self) static VALUE rb_dlptr_s_malloc(int argc, VALUE argv[], VALUE klass) { - VALUE size, sym, obj; + VALUE size, sym, obj, wrap = 0; long s; freefunc_t f; @@ -196,13 +210,14 @@ rb_dlptr_s_malloc(int argc, VALUE argv[], VALUE klass) break; case 2: s = NUM2LONG(size); - f = get_freefunc(sym); + f = get_freefunc(sym, &wrap); break; default: rb_bug("rb_dlptr_s_malloc"); } obj = rb_dlptr_malloc(s,f); + if (wrap) RPTR_DATA(obj)->wrap[1] = wrap; return obj; } @@ -289,7 +304,7 @@ rb_dlptr_free_set(VALUE self, VALUE val) struct ptr_data *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; } @@ -582,7 +597,7 @@ rb_dlptr_size_get(VALUE self) static VALUE 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))){ 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); if (rb_obj_is_kind_of(vptr, rb_cDLCPtr)){ ptr = vptr; + wrap = 0; } else{ rb_raise(rb_eDLError, "to_ptr should return a CPtr object"); } } 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); - rb_iv_set(ptr, "wrapping", val); + if (wrap) RPTR_DATA(ptr)->wrap[0] = wrap; return ptr; } diff --git a/ext/dl/dl.h b/ext/dl/dl.h index f893d8c2ae..90e2131ee2 100644 --- a/ext/dl/dl.h +++ b/ext/dl/dl.h @@ -199,6 +199,7 @@ struct cfunc_data { char *name; int type; ID calltype; + VALUE wrap; }; extern ID rbdl_id_cdecl; extern ID rbdl_id_stdcall; @@ -209,6 +210,7 @@ struct ptr_data { void *ptr; long size; freefunc_t free; + VALUE wrap[2]; }; #define RDL_HANDLE(obj) ((struct dl_handle *)(DATA_PTR(obj))) diff --git a/test/dl/test_func.rb b/test/dl/test_func.rb index 45d475c919..761ae43143 100644 --- a/test/dl/test_func.rb +++ b/test/dl/test_func.rb @@ -95,6 +95,11 @@ module DL buff = "9341" qsort.call(buff, buff.size, 1, cb) 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 def test_qsort2()