summaryrefslogtreecommitdiff
path: root/ext
diff options
context:
space:
mode:
authornaruse <naruse@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2012-02-14 20:09:27 +0000
committernaruse <naruse@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2012-02-14 20:09:27 +0000
commit35c546104b00e1e773bcdfd59bb0cd580c85b190 (patch)
tree976b1e7f7c88be80feaca6216b54a763458b9319 /ext
parent0c8cfb4eabc5c00e17439a61d274e8c74eefeef2 (diff)
merge revision(s) 32712,32718,32719: [Backport #6014]
* 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. * ext/dl/cptr.c (rb_dlptr_s_to_ptr): fix wrapping condition. * ext/dl/cptr.c (rb_dlptr_s_to_ptr): fix wrapping condition. * ext/dl/cptr.c (rb_dlptr_s_to_ptr): use rb_check_funcall. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_9_3@34604 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'ext')
-rw-r--r--ext/dl/cfunc.c16
-rw-r--r--ext/dl/cptr.c69
-rw-r--r--ext/dl/dl.h2
3 files changed, 58 insertions, 29 deletions
diff --git a/ext/dl/cfunc.c b/ext/dl/cfunc.c
index 677d0e1f4d..66aebf2e79 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 0f6271fd8e..89dcb942c0 100644
--- a/ext/dl/cptr.c
+++ b/ext/dl/cptr.c
@@ -10,20 +10,37 @@
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)
{
struct ptr_data *data = 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)));
- s = NUM2LONG(size);
- break;
- case 3:
- 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);
- 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;
}
@@ -588,7 +603,7 @@ rb_dlptr_size_get(VALUE self)
static VALUE
rb_dlptr_s_to_ptr(VALUE self, VALUE val)
{
- VALUE ptr;
+ VALUE ptr, wrap = val, vptr;
if (RTEST(rb_obj_is_kind_of(val, rb_cIO))){
rb_io_t *fptr;
@@ -601,20 +616,22 @@ rb_dlptr_s_to_ptr(VALUE self, VALUE val)
char *str = StringValuePtr(val);
ptr = rb_dlptr_new(str, RSTRING_LEN(val), NULL);
}
- else if (rb_respond_to(val, id_to_ptr)){
- VALUE vptr = rb_funcall(val, id_to_ptr, 0);
+ else if ((vptr = rb_check_funcall(val, id_to_ptr, 0, 0)) != Qundef){
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)))