From 1a2c653eb16b7bf6c3cd1214b3b19b3de66b5d2b Mon Sep 17 00:00:00 2001 From: Jean Boussier Date: Tue, 7 Feb 2023 12:19:07 +0100 Subject: [PATCH] Protect FFI::Function with Write Barrier Write barrier protected objects are allowed to be promoted to the old generation, which means they only get marked on major GC. The downside is that the `RB_BJ_WRITE` macro MUST be used to set references, otherwise the referenced object may be garbaged collected. --- ext/ffi_c/AbstractMemory.c | 45 ++++-------- ext/ffi_c/Buffer.c | 44 ++++++++---- ext/ffi_c/Call.c | 8 +-- ext/ffi_c/DynamicLibrary.c | 23 +++++-- ext/ffi_c/Function.c | 76 +++++++++++--------- ext/ffi_c/Pointer.c | 138 ++++++++++++++++--------------------- ext/ffi_c/Pointer.h | 11 +-- ext/ffi_c/Struct.c | 48 ++++++++----- 8 files changed, 199 insertions(+), 194 deletions(-) diff --git a/ext/ffi_c/AbstractMemory.c b/ext/ffi_c/AbstractMemory.c index 1a7fcde4d..7e6360003 100644 --- a/ext/ffi_c/AbstractMemory.c +++ b/ext/ffi_c/AbstractMemory.c @@ -86,8 +86,7 @@ static VALUE memory_put_##name(VALUE self, VALUE offset, VALUE value); \ static VALUE \ memory_put_##name(VALUE self, VALUE offset, VALUE value) \ { \ - AbstractMemory* memory; \ - Data_Get_Struct(self, AbstractMemory, memory); \ + AbstractMemory* memory = MEMORY(self); \ memory_op_put_##name(memory, NUM2LONG(offset), value); \ return self; \ } \ @@ -95,8 +94,7 @@ static VALUE memory_write_##name(VALUE self, VALUE value); \ static VALUE \ memory_write_##name(VALUE self, VALUE value) \ { \ - AbstractMemory* memory; \ - Data_Get_Struct(self, AbstractMemory, memory); \ + AbstractMemory* memory = MEMORY(self); \ memory_op_put_##name(memory, 0, value); \ return self; \ } \ @@ -114,16 +112,14 @@ static VALUE memory_get_##name(VALUE self, VALUE offset); \ static VALUE \ memory_get_##name(VALUE self, VALUE offset) \ { \ - AbstractMemory* memory; \ - Data_Get_Struct(self, AbstractMemory, memory); \ + AbstractMemory* memory = MEMORY(self); \ return memory_op_get_##name(memory, NUM2LONG(offset)); \ } \ static VALUE memory_read_##name(VALUE self); \ static VALUE \ memory_read_##name(VALUE self) \ { \ - AbstractMemory* memory; \ - Data_Get_Struct(self, AbstractMemory, memory); \ + AbstractMemory* memory = MEMORY(self); \ return memory_op_get_##name(memory, 0); \ } \ static MemoryOp memory_op_##name = { memory_op_get_##name, memory_op_put_##name }; \ @@ -319,11 +315,7 @@ memory_clear(VALUE self) static VALUE memory_size(VALUE self) { - AbstractMemory* ptr; - - Data_Get_Struct(self, AbstractMemory, ptr); - - return LONG2NUM(ptr->size); + return LONG2NUM(MEMORY_LEN(self)); } /* @@ -337,14 +329,13 @@ memory_size(VALUE self) static VALUE memory_get(VALUE self, VALUE type_name, VALUE offset) { - AbstractMemory* ptr; VALUE nType; Type *type; nType = rbffi_Type_Lookup(type_name); if(NIL_P(nType)) goto undefined_type; - Data_Get_Struct(self, AbstractMemory, ptr); + AbstractMemory* ptr = MEMORY(self); Data_Get_Struct(nType, Type, type); MemoryOp *op = get_memory_op(type); @@ -369,14 +360,13 @@ undefined_type: { static VALUE memory_put(VALUE self, VALUE type_name, VALUE offset, VALUE value) { - AbstractMemory* ptr; VALUE nType; Type *type; nType = rbffi_Type_Lookup(type_name); if(NIL_P(nType)) goto undefined_type; - Data_Get_Struct(self, AbstractMemory, ptr); + AbstractMemory* ptr = MEMORY(self); Data_Get_Struct(nType, Type, type); MemoryOp *op = get_memory_op(type); @@ -433,7 +423,6 @@ static VALUE memory_get_array_of_string(int argc, VALUE* argv, VALUE self) { VALUE offset = Qnil, countnum = Qnil, retVal = Qnil; - AbstractMemory* ptr; long off; int count; @@ -442,7 +431,7 @@ memory_get_array_of_string(int argc, VALUE* argv, VALUE self) count = (countnum == Qnil ? 0 : NUM2INT(countnum)); retVal = rb_ary_new2(count); - Data_Get_Struct(self, AbstractMemory, ptr); + AbstractMemory* ptr = MEMORY(self); checkRead(ptr); if (countnum != Qnil) { @@ -631,10 +620,7 @@ memory_write_bytes(int argc, VALUE* argv, VALUE self) static VALUE memory_type_size(VALUE self) { - AbstractMemory* ptr; - - Data_Get_Struct(self, AbstractMemory, ptr); - + AbstractMemory* ptr = MEMORY(self); return INT2NUM(ptr->typeSize); } @@ -648,11 +634,9 @@ memory_type_size(VALUE self) static VALUE memory_aref(VALUE self, VALUE idx) { - AbstractMemory* ptr; + AbstractMemory* ptr = MEMORY(self); VALUE rbOffset = Qnil; - Data_Get_Struct(self, AbstractMemory, ptr); - rbOffset = ULONG2NUM(NUM2ULONG(idx) * ptr->typeSize); return rb_funcall2(self, id_plus, 1, &rbOffset); @@ -667,11 +651,7 @@ memory_address(VALUE obj) static VALUE memory_copy_from(VALUE self, VALUE rbsrc, VALUE rblen) { - AbstractMemory* dst; - - Data_Get_Struct(self, AbstractMemory, dst); - - memcpy(dst->address, rbffi_AbstractMemory_Cast(rbsrc, rbffi_AbstractMemoryClass)->address, NUM2INT(rblen)); + memcpy(MEMORY_PTR(self), MEMORY_PTR(rbsrc), NUM2INT(rblen)); return self; } @@ -680,8 +660,7 @@ AbstractMemory* rbffi_AbstractMemory_Cast(VALUE obj, VALUE klass) { if (rb_obj_is_kind_of(obj, klass)) { - AbstractMemory* memory; - Data_Get_Struct(obj, AbstractMemory, memory); + AbstractMemory* memory = RTYPEDDATA_DATA(obj); return memory; } diff --git a/ext/ffi_c/Buffer.c b/ext/ffi_c/Buffer.c index b5f39a488..4e4f1d8ad 100644 --- a/ext/ffi_c/Buffer.c +++ b/ext/ffi_c/Buffer.c @@ -49,10 +49,20 @@ typedef struct Buffer { static VALUE buffer_allocate(VALUE klass); static VALUE buffer_initialize(int argc, VALUE* argv, VALUE self); -static void buffer_release(Buffer* ptr); -static void buffer_mark(Buffer* ptr); +static void buffer_release(void* data); +static void buffer_mark(void* data); static VALUE buffer_free(VALUE self); +static const rb_data_type_t buffer_data_type = { + .wrap_struct_name = "FFI::Buffer", + .function = { + .dmark = buffer_mark, + .dfree = buffer_release, + .dsize = NULL, + }, + .flags = RUBY_TYPED_FREE_IMMEDIATELY +}; + static VALUE BufferClass = Qnil; static VALUE @@ -61,7 +71,7 @@ buffer_allocate(VALUE klass) Buffer* buffer; VALUE obj; - obj = Data_Make_Struct(klass, Buffer, NULL, buffer_release, buffer); + obj = TypedData_Make_Struct(klass, Buffer, &buffer_data_type, buffer); buffer->data.rbParent = Qnil; buffer->memory.flags = MEM_RD | MEM_WR; @@ -69,8 +79,9 @@ buffer_allocate(VALUE klass) } static void -buffer_release(Buffer* ptr) +buffer_release(void *data) { + Buffer* ptr = (Buffer *)data; if ((ptr->memory.flags & MEM_EMBED) == 0 && ptr->data.storage != NULL) { xfree(ptr->data.storage); ptr->data.storage = NULL; @@ -95,7 +106,7 @@ buffer_initialize(int argc, VALUE* argv, VALUE self) Buffer* p; int nargs; - Data_Get_Struct(self, Buffer, p); + TypedData_Get_Struct(self, Buffer, &buffer_data_type, p); nargs = rb_scan_args(argc, argv, "12", &rbSize, &rbCount, &rbClear); p->memory.typeSize = rbffi_type_size(rbSize); @@ -138,7 +149,7 @@ buffer_initialize_copy(VALUE self, VALUE other) AbstractMemory* src; Buffer* dst; - Data_Get_Struct(self, Buffer, dst); + TypedData_Get_Struct(self, Buffer, &buffer_data_type, dst); src = rbffi_AbstractMemory_Cast(other, BufferClass); if ((dst->memory.flags & MEM_EMBED) == 0 && dst->data.storage != NULL) { xfree(dst->data.storage); @@ -172,10 +183,10 @@ slice(VALUE self, long offset, long len) Buffer* result; VALUE obj = Qnil; - Data_Get_Struct(self, Buffer, ptr); + TypedData_Get_Struct(self, Buffer, &buffer_data_type, ptr); checkBounds(&ptr->memory, offset, len); - obj = Data_Make_Struct(BufferClass, Buffer, buffer_mark, -1, result); + obj = TypedData_Make_Struct(BufferClass, Buffer, &buffer_data_type, result); result->memory.address = ptr->memory.address + offset; result->memory.size = len; result->memory.flags = ptr->memory.flags; @@ -197,7 +208,7 @@ buffer_plus(VALUE self, VALUE rbOffset) Buffer* ptr; long offset = NUM2LONG(rbOffset); - Data_Get_Struct(self, Buffer, ptr); + TypedData_Get_Struct(self, Buffer, &buffer_data_type, ptr); return slice(self, offset, ptr->memory.size - offset); } @@ -226,7 +237,7 @@ buffer_inspect(VALUE self) char tmp[100]; Buffer* ptr; - Data_Get_Struct(self, Buffer, ptr); + TypedData_Get_Struct(self, Buffer, &buffer_data_type, ptr); snprintf(tmp, sizeof(tmp), "#", ptr, ptr->memory.address, ptr->memory.size); @@ -255,7 +266,7 @@ buffer_order(int argc, VALUE* argv, VALUE self) { Buffer* ptr; - Data_Get_Struct(self, Buffer, ptr); + TypedData_Get_Struct(self, Buffer, &buffer_data_type, ptr); if (argc == 0) { int order = (ptr->memory.flags & MEM_SWAP) == 0 ? BYTE_ORDER : SWAPPED_ORDER; return order == BIG_ENDIAN ? ID2SYM(rb_intern("big")) : ID2SYM(rb_intern("little")); @@ -279,7 +290,7 @@ buffer_order(int argc, VALUE* argv, VALUE self) Buffer* p2; VALUE retval = slice(self, 0, ptr->memory.size); - Data_Get_Struct(retval, Buffer, p2); + TypedData_Get_Struct(retval, Buffer, &buffer_data_type, p2); p2->memory.flags |= MEM_SWAP; return retval; } @@ -294,7 +305,7 @@ buffer_free(VALUE self) { Buffer* ptr; - Data_Get_Struct(self, Buffer, ptr); + TypedData_Get_Struct(self, Buffer, &buffer_data_type, ptr); if ((ptr->memory.flags & MEM_EMBED) == 0 && ptr->data.storage != NULL) { xfree(ptr->data.storage); ptr->data.storage = NULL; @@ -304,9 +315,12 @@ buffer_free(VALUE self) } static void -buffer_mark(Buffer* ptr) +buffer_mark(void *data) { - rb_gc_mark(ptr->data.rbParent); + Buffer* ptr = (Buffer *)data; + if ((ptr->memory.flags & MEM_EMBED) != 0) { + rb_gc_mark(ptr->data.rbParent); + } } void diff --git a/ext/ffi_c/Call.c b/ext/ffi_c/Call.c index bd6c2776b..098456577 100644 --- a/ext/ffi_c/Call.c +++ b/ext/ffi_c/Call.c @@ -439,7 +439,7 @@ getPointer(VALUE value, int type) VALUE ptr = rb_funcall2(value, id_to_ptr, 0, NULL); if (rb_obj_is_kind_of(ptr, rbffi_AbstractMemoryClass) && TYPE(ptr) == T_DATA) { - return ((AbstractMemory *) DATA_PTR(ptr))->address; + return MEMORY_PTR(ptr); } rb_raise(rb_eArgError, "to_ptr returned an invalid pointer"); } @@ -465,15 +465,13 @@ callback_param(VALUE proc, VALUE cbInfo) /* Handle Function pointers here */ if (rb_obj_is_kind_of(proc, rbffi_FunctionClass)) { - AbstractMemory* ptr; - Data_Get_Struct(proc, AbstractMemory, ptr); - return ptr->address; + return MEMORY_PTR(proc); } callback = rbffi_Function_ForProc(cbInfo, proc); RB_GC_GUARD(callback); - return ((AbstractMemory *) DATA_PTR(callback))->address; + return MEMORY_PTR(callback); } diff --git a/ext/ffi_c/DynamicLibrary.c b/ext/ffi_c/DynamicLibrary.c index 78b3de60e..1923cdc08 100644 --- a/ext/ffi_c/DynamicLibrary.c +++ b/ext/ffi_c/DynamicLibrary.c @@ -57,10 +57,19 @@ typedef struct LibrarySymbol_ { static VALUE library_initialize(VALUE self, VALUE libname, VALUE libflags); static void library_free(Library* lib); - static VALUE symbol_allocate(VALUE klass); static VALUE symbol_new(VALUE library, void* address, VALUE name); -static void symbol_mark(LibrarySymbol* sym); +static void symbol_mark(void *); + +static const rb_data_type_t symbol_data_type = { + .wrap_struct_name = "FFI::DynamicLibrary::Symbol", + .function = { + .dmark = symbol_mark, + .dfree = RUBY_DEFAULT_FREE, + .dsize = NULL, + }, + .flags = RUBY_TYPED_FREE_IMMEDIATELY +}; static VALUE LibraryClass = Qnil, SymbolClass = Qnil; @@ -198,7 +207,7 @@ static VALUE symbol_allocate(VALUE klass) { LibrarySymbol* sym; - VALUE obj = Data_Make_Struct(klass, LibrarySymbol, NULL, -1, sym); + VALUE obj = TypedData_Make_Struct(SymbolClass, LibrarySymbol, &symbol_data_type, sym); sym->name = Qnil; sym->library = Qnil; sym->base.rbParent = Qnil; @@ -224,7 +233,7 @@ static VALUE symbol_new(VALUE library, void* address, VALUE name) { LibrarySymbol* sym; - VALUE obj = Data_Make_Struct(SymbolClass, LibrarySymbol, symbol_mark, -1, sym); + VALUE obj = TypedData_Make_Struct(SymbolClass, LibrarySymbol, &symbol_data_type, sym); sym->base.memory.address = address; sym->base.memory.size = LONG_MAX; @@ -237,10 +246,12 @@ symbol_new(VALUE library, void* address, VALUE name) } static void -symbol_mark(LibrarySymbol* sym) +symbol_mark(void *data) { + LibrarySymbol *sym = (LibrarySymbol *)data; rb_gc_mark(sym->library); rb_gc_mark(sym->name); + rb_gc_mark(sym->base.rbParent); } /* @@ -254,7 +265,7 @@ symbol_inspect(VALUE self) LibrarySymbol* sym; char buf[256]; - Data_Get_Struct(self, LibrarySymbol, sym); + TypedData_Get_Struct(self, LibrarySymbol, &symbol_data_type, sym); snprintf(buf, sizeof(buf), "#", StringValueCStr(sym->name), sym->base.memory.address); return rb_str_new2(buf); diff --git a/ext/ffi_c/Function.c b/ext/ffi_c/Function.c index 1a575911c..083245f38 100644 --- a/ext/ffi_c/Function.c +++ b/ext/ffi_c/Function.c @@ -75,8 +75,6 @@ typedef struct Function_ { VALUE rbFunctionInfo; } Function; -static void function_mark(Function *); -static void function_free(Function *); static VALUE function_init(VALUE self, VALUE rbFunctionInfo, VALUE rbProc); static void callback_invoke(ffi_cif* cif, void* retval, void** parameters, void* user_data); static bool callback_prep(void* ctx, void* code, Closure* closure, char* errmsg, size_t errmsgsize); @@ -132,35 +130,19 @@ static struct gvl_callback* async_cb_list = NULL; # endif #endif - -static VALUE -function_allocate(VALUE klass) -{ - Function *fn; - VALUE obj; - - obj = Data_Make_Struct(klass, Function, function_mark, function_free, fn); - - fn->base.memory.flags = MEM_RD; - fn->base.rbParent = Qnil; - fn->rbProc = Qnil; - fn->rbFunctionInfo = Qnil; - fn->autorelease = true; - - return obj; -} - static void -function_mark(Function *fn) +function_mark(void *data) { + Function *fn = (Function *)data; rb_gc_mark(fn->base.rbParent); rb_gc_mark(fn->rbProc); rb_gc_mark(fn->rbFunctionInfo); } static void -function_free(Function *fn) +function_free(void *data) { + Function *fn = (Function *)data; if (fn->methodHandle != NULL) { rbffi_MethodHandle_Free(fn->methodHandle); } @@ -172,6 +154,33 @@ function_free(Function *fn) xfree(fn); } +static const rb_data_type_t function_data_type = { + .wrap_struct_name = "FFI::Function", + .function = { + .dmark = function_mark, + .dfree = function_free, + .dsize = NULL, + }, + .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED +}; + +static VALUE +function_allocate(VALUE klass) +{ + Function *fn; + VALUE obj; + + obj = TypedData_Make_Struct(klass, Function, &function_data_type, fn); + + fn->base.memory.flags = MEM_RD; + fn->base.rbParent = Qnil; + fn->rbProc = Qnil; + fn->rbFunctionInfo = Qnil; + fn->autorelease = true; + + return obj; +} + /* * @param [Type, Symbol] return_type return type for the function * @param [Array] param_types array of parameters types @@ -254,7 +263,7 @@ rbffi_Function_ForProc(VALUE rbFunctionInfo, VALUE proc) /* If the first callback reference has the same function function signature, use it */ if (cbref != Qnil && CLASS_OF(cbref) == rbffi_FunctionClass) { Function* fp; - Data_Get_Struct(cbref, Function, fp); + TypedData_Get_Struct(cbref, Function, &function_data_type, fp); if (fp->rbFunctionInfo == rbFunctionInfo) { return cbref; } @@ -298,17 +307,16 @@ function_init(VALUE self, VALUE rbFunctionInfo, VALUE rbProc) { Function* fn = NULL; - Data_Get_Struct(self, Function, fn); + TypedData_Get_Struct(self, Function, &function_data_type, fn); - fn->rbFunctionInfo = rbFunctionInfo; + RB_OBJ_WRITE(self, &fn->rbFunctionInfo, rbFunctionInfo); Data_Get_Struct(fn->rbFunctionInfo, FunctionType, fn->info); if (rb_obj_is_kind_of(rbProc, rbffi_PointerClass)) { - Pointer* orig; - Data_Get_Struct(rbProc, Pointer, orig); + Pointer* orig = rbffi_Pointer_Cast(rbProc, rbffi_PointerClass); fn->base.memory = orig->memory; - fn->base.rbParent = rbProc; + RB_OBJ_WRITE(self, &fn->base.rbParent, rbProc); } else if (rb_obj_is_kind_of(rbProc, rb_cProc) || rb_respond_to(rbProc, id_call)) { if (fn->info->closurePool == NULL) { @@ -344,7 +352,7 @@ function_init(VALUE self, VALUE rbFunctionInfo, VALUE rbProc) rb_obj_classname(rbProc)); } - fn->rbProc = rbProc; + RB_OBJ_WRITE(self, &fn->rbProc, rbProc); return self; } @@ -360,7 +368,7 @@ function_call(int argc, VALUE* argv, VALUE self) { Function* fn; - Data_Get_Struct(self, Function, fn); + TypedData_Get_Struct(self, Function, &function_data_type, fn); return (*fn->info->invoke)(argc, argv, fn->base.memory.address, fn->info); } @@ -378,7 +386,7 @@ function_attach(VALUE self, VALUE module, VALUE name) Function* fn; char var[1024]; - Data_Get_Struct(self, Function, fn); + TypedData_Get_Struct(self, Function, &function_data_type, fn); if (fn->info->parameterCount == -1) { rb_raise(rb_eRuntimeError, "cannot attach variadic functions"); @@ -421,7 +429,7 @@ function_set_autorelease(VALUE self, VALUE autorelease) { Function* fn; - Data_Get_Struct(self, Function, fn); + TypedData_Get_Struct(self, Function, &function_data_type, fn); fn->autorelease = RTEST(autorelease); @@ -433,7 +441,7 @@ function_autorelease_p(VALUE self) { Function* fn; - Data_Get_Struct(self, Function, fn); + TypedData_Get_Struct(self, Function, &function_data_type, fn); return fn->autorelease ? Qtrue : Qfalse; } @@ -448,7 +456,7 @@ function_release(VALUE self) { Function* fn; - Data_Get_Struct(self, Function, fn); + TypedData_Get_Struct(self, Function, &function_data_type, fn); if (fn->closure == NULL) { rb_raise(rb_eRuntimeError, "cannot free function which was not allocated"); diff --git a/ext/ffi_c/Pointer.c b/ext/ffi_c/Pointer.c index 79886811f..89115a458 100644 --- a/ext/ffi_c/Pointer.c +++ b/ext/ffi_c/Pointer.c @@ -36,13 +36,50 @@ #include "AbstractMemory.h" #include "Pointer.h" -#define POINTER(obj) rbffi_AbstractMemory_Cast((obj), rbffi_PointerClass) +#define POINTER(obj) rbffi_Pointer_Cast((obj), rbffi_PointerClass) VALUE rbffi_PointerClass = Qnil; VALUE rbffi_NullPointerSingleton = Qnil; -static void ptr_release(Pointer* ptr); -static void ptr_mark(Pointer* ptr); +static void +ptr_release(void *data) +{ + Pointer *ptr = (Pointer *)data; + if (ptr->autorelease && ptr->allocated && ptr->storage != NULL) { + xfree(ptr->storage); + ptr->storage = NULL; + } + xfree(ptr); +} + +static void +ptr_mark(void *data) +{ + Pointer *ptr = (Pointer *)data; + rb_gc_mark(ptr->rbParent); +} + +static const rb_data_type_t pointer_data_type = { + .wrap_struct_name = "FFI::Pointer", + .function = { + .dmark = ptr_mark, + .dfree = ptr_release, + .dsize = NULL, + }, + .flags = RUBY_TYPED_FREE_IMMEDIATELY +}; + +Pointer* +rbffi_Pointer_Cast(VALUE obj, VALUE klass) +{ + if (rb_obj_is_kind_of(obj, klass)) { + Pointer* ptr = RTYPEDDATA_DATA(obj); + return ptr; + } + + rb_raise(rb_eArgError, "Invalid Pointer object"); + return NULL; +} VALUE rbffi_Pointer_NewInstance(void* addr) @@ -54,7 +91,7 @@ rbffi_Pointer_NewInstance(void* addr) return rbffi_NullPointerSingleton; } - obj = Data_Make_Struct(rbffi_PointerClass, Pointer, NULL, -1, p); + obj = TypedData_Make_Struct(rbffi_PointerClass, Pointer, &pointer_data_type, p); p->memory.address = addr; p->memory.size = LONG_MAX; p->memory.flags = (addr == NULL) ? 0 : (MEM_RD | MEM_WR); @@ -70,7 +107,7 @@ ptr_allocate(VALUE klass) Pointer* p; VALUE obj; - obj = Data_Make_Struct(klass, Pointer, ptr_mark, ptr_release, p); + obj = TypedData_Make_Struct(klass, Pointer, &pointer_data_type, p); p->rbParent = Qnil; p->memory.flags = MEM_RD | MEM_WR; @@ -91,12 +128,10 @@ ptr_allocate(VALUE klass) static VALUE ptr_initialize(int argc, VALUE* argv, VALUE self) { - Pointer* p; + Pointer* p = POINTER(self); VALUE rbType = Qnil, rbAddress = Qnil; int typeSize = 1; - Data_Get_Struct(self, Pointer, p); - switch (rb_scan_args(argc, argv, "11", &rbType, &rbAddress)) { case 1: rbAddress = rbType; @@ -121,10 +156,8 @@ ptr_initialize(int argc, VALUE* argv, VALUE self) default: if (rb_obj_is_kind_of(rbAddress, rbffi_PointerClass)) { - Pointer* orig; - p->rbParent = rbAddress; - Data_Get_Struct(rbAddress, Pointer, orig); + Pointer* orig = POINTER(rbAddress); p->memory = orig->memory; } else { rb_raise(rb_eTypeError, "wrong argument type, expected Integer or FFI::Pointer"); @@ -150,11 +183,9 @@ ptr_initialize(int argc, VALUE* argv, VALUE self) static VALUE ptr_initialize_copy(VALUE self, VALUE other) { - AbstractMemory* src; - Pointer* dst; + AbstractMemory* src = MEMORY(other); + Pointer* dst = POINTER(self); - Data_Get_Struct(self, Pointer, dst); - src = POINTER(other); if (src->size == LONG_MAX) { rb_raise(rb_eRuntimeError, "cannot duplicate unbounded memory area"); return Qnil; @@ -191,11 +222,10 @@ ptr_initialize_copy(VALUE self, VALUE other) static VALUE slice(VALUE self, long offset, long size) { - AbstractMemory* ptr; + AbstractMemory* ptr = MEMORY(self); Pointer* p; VALUE retval; - Data_Get_Struct(self, AbstractMemory, ptr); checkBounds(ptr, offset, size == LONG_MAX ? 1 : size); retval = Data_Make_Struct(rbffi_PointerClass, Pointer, ptr_mark, -1, p); @@ -219,12 +249,9 @@ slice(VALUE self, long offset, long size) static VALUE ptr_plus(VALUE self, VALUE offset) { - AbstractMemory* ptr; long off = NUM2LONG(offset); - - Data_Get_Struct(self, AbstractMemory, ptr); - - return slice(self, off, ptr->size == LONG_MAX ? LONG_MAX : ptr->size - off); + long size = MEMORY_LEN(self); + return slice(self, off, size == LONG_MAX ? LONG_MAX : size - off); } /* @@ -250,9 +277,7 @@ static VALUE ptr_inspect(VALUE self) { char buf[100]; - Pointer* ptr; - - Data_Get_Struct(self, Pointer, ptr); + Pointer* ptr = POINTER(self); if (ptr->memory.size != LONG_MAX) { snprintf(buf, sizeof(buf), "#<%s address=%p size=%lu>", @@ -273,11 +298,7 @@ ptr_inspect(VALUE self) static VALUE ptr_null_p(VALUE self) { - Pointer* ptr; - - Data_Get_Struct(self, Pointer, ptr); - - return ptr->memory.address == NULL ? Qtrue : Qfalse; + return MEMORY_PTR(self) == NULL ? Qtrue : Qfalse; } /* @@ -289,15 +310,11 @@ ptr_null_p(VALUE self) static VALUE ptr_equals(VALUE self, VALUE other) { - Pointer* ptr; - - Data_Get_Struct(self, Pointer, ptr); - if (NIL_P(other)) { - return ptr->memory.address == NULL ? Qtrue : Qfalse; + return MEMORY_PTR(self) == NULL ? Qtrue : Qfalse; } - return ptr->memory.address == POINTER(other)->address ? Qtrue : Qfalse; + return MEMORY_PTR(self) == MEMORY_PTR(other) ? Qtrue : Qfalse; } /* @@ -308,11 +325,7 @@ ptr_equals(VALUE self, VALUE other) static VALUE ptr_address(VALUE self) { - Pointer* ptr; - - Data_Get_Struct(self, Pointer, ptr); - - return ULL2NUM((uintptr_t) ptr->memory.address); + return ULL2NUM((uintptr_t)MEMORY_PTR(self)); } #if BYTE_ORDER == LITTLE_ENDIAN @@ -333,9 +346,8 @@ ptr_address(VALUE self) static VALUE ptr_order(int argc, VALUE* argv, VALUE self) { - Pointer* ptr; + Pointer* ptr = POINTER(self); - Data_Get_Struct(self, Pointer, ptr); if (argc == 0) { int order = (ptr->memory.flags & MEM_SWAP) == 0 ? BYTE_ORDER : SWAPPED_ORDER; return order == BIG_ENDIAN ? ID2SYM(rb_intern("big")) : ID2SYM(rb_intern("little")); @@ -358,10 +370,8 @@ ptr_order(int argc, VALUE* argv, VALUE self) } } if (order != BYTE_ORDER) { - Pointer* p2; VALUE retval = slice(self, 0, ptr->memory.size); - - Data_Get_Struct(retval, Pointer, p2); + Pointer* p2 = POINTER(retval); p2->memory.flags |= MEM_SWAP; return retval; } @@ -379,9 +389,7 @@ ptr_order(int argc, VALUE* argv, VALUE self) static VALUE ptr_free(VALUE self) { - Pointer* ptr; - - Data_Get_Struct(self, Pointer, ptr); + Pointer* ptr = POINTER(self); if (ptr->allocated) { if (ptr->storage != NULL) { @@ -402,10 +410,7 @@ ptr_free(VALUE self) static VALUE ptr_type_size(VALUE self) { - Pointer* ptr; - - Data_Get_Struct(self, Pointer, ptr); - + Pointer* ptr = POINTER(self); return INT2NUM(ptr->memory.typeSize); } @@ -418,11 +423,8 @@ ptr_type_size(VALUE self) static VALUE ptr_autorelease(VALUE self, VALUE autorelease) { - Pointer* ptr; - - Data_Get_Struct(self, Pointer, ptr); + Pointer* ptr = POINTER(self); ptr->autorelease = autorelease == Qtrue; - return autorelease; } @@ -434,30 +436,10 @@ ptr_autorelease(VALUE self, VALUE autorelease) static VALUE ptr_autorelease_p(VALUE self) { - Pointer* ptr; - - Data_Get_Struct(self, Pointer, ptr); - + Pointer* ptr = POINTER(self); return ptr->autorelease ? Qtrue : Qfalse; } - -static void -ptr_release(Pointer* ptr) -{ - if (ptr->autorelease && ptr->allocated && ptr->storage != NULL) { - xfree(ptr->storage); - ptr->storage = NULL; - } - xfree(ptr); -} - -static void -ptr_mark(Pointer* ptr) -{ - rb_gc_mark(ptr->rbParent); -} - void rbffi_Pointer_Init(VALUE moduleFFI) { diff --git a/ext/ffi_c/Pointer.h b/ext/ffi_c/Pointer.h index b3d6c85f1..e58d97aec 100644 --- a/ext/ffi_c/Pointer.h +++ b/ext/ffi_c/Pointer.h @@ -38,11 +38,6 @@ extern "C" { #include "AbstractMemory.h" -extern void rbffi_Pointer_Init(VALUE moduleFFI); -extern VALUE rbffi_Pointer_NewInstance(void* addr); -extern VALUE rbffi_PointerClass; -extern VALUE rbffi_NullPointerSingleton; - typedef struct Pointer { AbstractMemory memory; VALUE rbParent; @@ -51,6 +46,12 @@ typedef struct Pointer { bool allocated; } Pointer; +extern void rbffi_Pointer_Init(VALUE moduleFFI); +extern VALUE rbffi_Pointer_NewInstance(void* addr); +extern Pointer *rbffi_Pointer_Cast(VALUE obj, VALUE klass); +extern VALUE rbffi_PointerClass; +extern VALUE rbffi_NullPointerSingleton; + #ifdef __cplusplus } #endif diff --git a/ext/ffi_c/Struct.c b/ext/ffi_c/Struct.c index 92731c813..5a6fb3c76 100644 --- a/ext/ffi_c/Struct.c +++ b/ext/ffi_c/Struct.c @@ -61,8 +61,8 @@ typedef struct InlineArray_ { } InlineArray; -static void struct_mark(Struct *); -static void struct_free(Struct *); +static void struct_mark(void *); +static void struct_free(void *); static VALUE struct_class_layout(VALUE klass); static void struct_malloc(Struct* s); static void inline_array_mark(InlineArray *); @@ -76,6 +76,16 @@ VALUE rbffi_StructLayoutCharArrayClass = Qnil; static ID id_pointer_ivar = 0, id_layout_ivar = 0; static ID id_get = 0, id_put = 0, id_to_ptr = 0, id_to_s = 0, id_layout = 0; +static const rb_data_type_t struct_data_type = { + .wrap_struct_name = "FFI::Struct", + .function = { + .dmark = struct_mark, + .dfree = struct_free, + .dsize = NULL, + }, + .flags = RUBY_TYPED_FREE_IMMEDIATELY +}; + static inline char* memory_address(VALUE self) { @@ -86,7 +96,7 @@ static VALUE struct_allocate(VALUE klass) { Struct* s; - VALUE obj = Data_Make_Struct(klass, Struct, struct_mark, struct_free, s); + VALUE obj = TypedData_Make_Struct(klass, Struct, &struct_data_type, s); s->rbPointer = Qnil; s->rbLayout = Qnil; @@ -108,7 +118,7 @@ struct_initialize(int argc, VALUE* argv, VALUE self) VALUE rbPointer = Qnil, rest = Qnil, klass = CLASS_OF(self); int nargs; - Data_Get_Struct(self, Struct, s); + TypedData_Get_Struct(self, Struct, &struct_data_type, s); nargs = rb_scan_args(argc, argv, "01*", &rbPointer, &rest); @@ -146,8 +156,8 @@ struct_initialize_copy(VALUE self, VALUE other) Struct* src; Struct* dst; - Data_Get_Struct(self, Struct, dst); - Data_Get_Struct(other, Struct, src); + TypedData_Get_Struct(self, Struct, &struct_data_type, dst); + TypedData_Get_Struct(other, Struct, &struct_data_type, src); if (dst == src) { return self; } @@ -213,7 +223,7 @@ static Struct* struct_validate(VALUE self) { Struct* s; - Data_Get_Struct(self, Struct, s); + TypedData_Get_Struct(self, Struct, &struct_data_type, s); if (struct_layout(self) == NULL) { rb_raise(rb_eRuntimeError, "struct layout == null"); @@ -240,8 +250,9 @@ struct_malloc(Struct* s) } static void -struct_mark(Struct *s) +struct_mark(void *data) { + Struct *s = (Struct *)data; rb_gc_mark(s->rbPointer); rb_gc_mark(s->rbLayout); if (s->rbReferences != NULL) { @@ -250,8 +261,9 @@ struct_mark(Struct *s) } static void -struct_free(Struct* s) +struct_free(void *data) { + Struct *s = (Struct *)data; xfree(s->rbReferences); xfree(s); } @@ -383,7 +395,7 @@ struct_set_pointer(VALUE self, VALUE pointer) } - Data_Get_Struct(self, Struct, s); + TypedData_Get_Struct(self, Struct, &struct_data_type, s); Data_Get_Struct(pointer, AbstractMemory, memory); layout = struct_layout(self); @@ -409,7 +421,7 @@ struct_get_pointer(VALUE self) { Struct* s; - Data_Get_Struct(self, Struct, s); + TypedData_Get_Struct(self, Struct, &struct_data_type, s); return s->rbPointer; } @@ -424,7 +436,7 @@ static VALUE struct_set_layout(VALUE self, VALUE layout) { Struct* s; - Data_Get_Struct(self, Struct, s); + TypedData_Get_Struct(self, Struct, &struct_data_type, s); if (!rb_obj_is_kind_of(layout, rbffi_StructLayoutClass)) { rb_raise(rb_eTypeError, "wrong argument type %s (expected %s)", @@ -448,7 +460,7 @@ struct_get_layout(VALUE self) { Struct* s; - Data_Get_Struct(self, Struct, s); + TypedData_Get_Struct(self, Struct, &struct_data_type, s); return s->rbLayout; } @@ -463,7 +475,7 @@ struct_null_p(VALUE self) { Struct* s; - Data_Get_Struct(self, Struct, s); + TypedData_Get_Struct(self, Struct, &struct_data_type, s); return s->pointer->address == NULL ? Qtrue : Qfalse; } @@ -476,7 +488,7 @@ struct_order(int argc, VALUE* argv, VALUE self) { Struct* s; - Data_Get_Struct(self, Struct, s); + TypedData_Get_Struct(self, Struct, &struct_data_type, s); if (argc == 0) { return rb_funcall(s->rbPointer, rb_intern("order"), 0); @@ -495,7 +507,7 @@ inline_array_allocate(VALUE klass) InlineArray* array; VALUE obj; - obj = Data_Make_Struct(klass, InlineArray, inline_array_mark, -1, array); + obj = Data_Make_Struct(klass, InlineArray, inline_array_mark, RUBY_DEFAULT_FREE, array); array->rbField = Qnil; array->rbMemory = Qnil; @@ -525,7 +537,7 @@ inline_array_initialize(VALUE self, VALUE rbMemory, VALUE rbField) array->rbMemory = rbMemory; array->rbField = rbField; - Data_Get_Struct(rbMemory, AbstractMemory, array->memory); + array->memory = rbffi_AbstractMemory_Cast(rbMemory, rbffi_AbstractMemoryClass); Data_Get_Struct(rbField, StructField, array->field); Data_Get_Struct(array->field->rbType, ArrayType, array->arrayType); Data_Get_Struct(array->arrayType->rbComponentType, Type, array->componentType); @@ -633,7 +645,7 @@ inline_array_aset(VALUE self, VALUE rbIndex, VALUE rbValue) checkWrite(array->memory); checkBounds(array->memory, offset, array->componentType->ffiType->size); - Data_Get_Struct(rbValue, Struct, s); + TypedData_Get_Struct(rbValue, Struct, &struct_data_type, s); checkRead(s->pointer); checkBounds(s->pointer, 0, array->componentType->ffiType->size);