From ae7b53546ca18b56c23f612b6935e98268a07602 Mon Sep 17 00:00:00 2001 From: Sutou Kouhei Date: Thu, 9 Jul 2020 20:19:20 +0900 Subject: [ruby/fiddle] Add TYPE_CONST_STRING and SIZEOF_CONST_STRING for "const char *" Add rb_fiddle_ prefix to conversion functions.h to keep backward compatibility but value_to_generic() isn't safe for TYPE_CONST_STRING and not String src. Use rb_fiddle_value_to_generic() instead. https://github.com/ruby/fiddle/commit/0ffcaa39e5 --- ext/fiddle/conversions.c | 69 +++++++++++++++++++++++++++++++---------- ext/fiddle/conversions.h | 17 +++++++--- ext/fiddle/fiddle.c | 12 +++++++ ext/fiddle/fiddle.h | 1 + ext/fiddle/function.c | 13 ++++++++ ext/fiddle/lib/fiddle/import.rb | 2 ++ 6 files changed, 94 insertions(+), 20 deletions(-) (limited to 'ext') diff --git a/ext/fiddle/conversions.c b/ext/fiddle/conversions.c index d40ddc1f38..19bdd8a896 100644 --- a/ext/fiddle/conversions.c +++ b/ext/fiddle/conversions.c @@ -1,7 +1,7 @@ #include ffi_type * -int_to_ffi_type(int type) +rb_fiddle_int_to_ffi_type(int type) { int signed_p = 1; @@ -33,66 +33,90 @@ int_to_ffi_type(int type) return &ffi_type_float; case TYPE_DOUBLE: return &ffi_type_double; + case TYPE_CONST_STRING: + return &ffi_type_pointer; default: rb_raise(rb_eRuntimeError, "unknown type %d", type); } return &ffi_type_pointer; } +ffi_type * +int_to_ffi_type(int type) +{ + return rb_fiddle_int_to_ffi_type(type); +} + void -value_to_generic(int type, VALUE src, fiddle_generic * dst) +rb_fiddle_value_to_generic(int type, VALUE *src, fiddle_generic *dst) { switch (type) { case TYPE_VOID: break; case TYPE_VOIDP: - dst->pointer = NUM2PTR(rb_Integer(src)); + dst->pointer = NUM2PTR(rb_Integer(*src)); break; case TYPE_CHAR: - dst->schar = (signed char)NUM2INT(src); + dst->schar = (signed char)NUM2INT(*src); break; case -TYPE_CHAR: - dst->uchar = (unsigned char)NUM2UINT(src); + dst->uchar = (unsigned char)NUM2UINT(*src); break; case TYPE_SHORT: - dst->sshort = (unsigned short)NUM2INT(src); + dst->sshort = (unsigned short)NUM2INT(*src); break; case -TYPE_SHORT: - dst->sshort = (signed short)NUM2UINT(src); + dst->sshort = (signed short)NUM2UINT(*src); break; case TYPE_INT: - dst->sint = NUM2INT(src); + dst->sint = NUM2INT(*src); break; case -TYPE_INT: - dst->uint = NUM2UINT(src); + dst->uint = NUM2UINT(*src); break; case TYPE_LONG: - dst->slong = NUM2LONG(src); + dst->slong = NUM2LONG(*src); break; case -TYPE_LONG: - dst->ulong = NUM2ULONG(src); + dst->ulong = NUM2ULONG(*src); break; #if HAVE_LONG_LONG case TYPE_LONG_LONG: - dst->slong_long = NUM2LL(src); + dst->slong_long = NUM2LL(*src); break; case -TYPE_LONG_LONG: - dst->ulong_long = NUM2ULL(src); + dst->ulong_long = NUM2ULL(*src); break; #endif case TYPE_FLOAT: - dst->ffloat = (float)NUM2DBL(src); + dst->ffloat = (float)NUM2DBL(*src); break; case TYPE_DOUBLE: - dst->ddouble = NUM2DBL(src); + dst->ddouble = NUM2DBL(*src); + break; + case TYPE_CONST_STRING: + if (NIL_P(*src)) { + dst->pointer = NULL; + } + else { + dst->pointer = rb_string_value_cstr(src); + } break; default: rb_raise(rb_eRuntimeError, "unknown type %d", type); } } +void +value_to_generic(int type, VALUE src, fiddle_generic *dst) +{ + /* src isn't safe from GC when type is TYPE_CONST_STRING and src + * isn't String. */ + return rb_fiddle_value_to_generic(type, &src, dst); +} + VALUE -generic_to_value(VALUE rettype, fiddle_generic retval) +rb_fiddle_generic_to_value(VALUE rettype, fiddle_generic retval) { int type = NUM2INT(rettype); VALUE cPointer; @@ -131,6 +155,13 @@ generic_to_value(VALUE rettype, fiddle_generic retval) return rb_float_new(retval.ffloat); case TYPE_DOUBLE: return rb_float_new(retval.ddouble); + case TYPE_CONST_STRING: + if (retval.pointer) { + return rb_str_new_cstr(retval.pointer); + } + else { + return Qnil; + } default: rb_raise(rb_eRuntimeError, "unknown type %d", type); } @@ -138,4 +169,10 @@ generic_to_value(VALUE rettype, fiddle_generic retval) UNREACHABLE; } +VALUE +generic_to_value(VALUE rettype, fiddle_generic retval) +{ + return rb_fiddle_generic_to_value(rettype, retval); +} + /* vim: set noet sw=4 sts=4 */ diff --git a/ext/fiddle/conversions.h b/ext/fiddle/conversions.h index cbc610bad2..f900efa9ad 100644 --- a/ext/fiddle/conversions.h +++ b/ext/fiddle/conversions.h @@ -24,13 +24,22 @@ typedef union void * pointer; /* ffi_type_pointer */ } fiddle_generic; +/* Deprecated. Use rb_fiddle_*() version. */ +ffi_type * rb_fiddle_int_to_ffi_type(int type); +void rb_fiddle_value_to_generic(int type, VALUE *src, fiddle_generic *dst); +VALUE rb_fiddle_generic_to_value(VALUE rettype, fiddle_generic retval); + +/* Deprecated. Use rb_fiddle_*() version. */ ffi_type * int_to_ffi_type(int type); -void value_to_generic(int type, VALUE src, fiddle_generic * dst); +void value_to_generic(int type, VALUE src, fiddle_generic *dst); VALUE generic_to_value(VALUE rettype, fiddle_generic retval); -#define VALUE2GENERIC(_type, _src, _dst) value_to_generic((_type), (_src), (_dst)) -#define INT2FFI_TYPE(_type) int_to_ffi_type(_type) -#define GENERIC2VALUE(_type, _retval) generic_to_value((_type), (_retval)) +#define VALUE2GENERIC(_type, _src, _dst) \ + rb_fiddle_value_to_generic((_type), &(_src), (_dst)) +#define INT2FFI_TYPE(_type) \ + rb_fiddle_int_to_ffi_type(_type) +#define GENERIC2VALUE(_type, _retval) \ + rb_fiddle_generic_to_value((_type), (_retval)) #if SIZEOF_VOIDP == SIZEOF_LONG # define PTR2NUM(x) (LONG2NUM((long)(x))) diff --git a/ext/fiddle/fiddle.c b/ext/fiddle/fiddle.c index 8fb20e8ce2..be287e6fdb 100644 --- a/ext/fiddle/fiddle.c +++ b/ext/fiddle/fiddle.c @@ -235,6 +235,12 @@ Init_fiddle(void) rb_define_const(mFiddle, "TYPE_VARIADIC", INT2NUM(TYPE_VARIADIC)); #endif + /* Document-const: TYPE_CONST_STRING + * + * C type - const char* ('\0' terminated const char*) + */ + rb_define_const(mFiddle, "TYPE_CONST_STRING", INT2NUM(TYPE_CONST_STRING)); + /* Document-const: TYPE_SIZE_T * * C type - size_t @@ -435,6 +441,12 @@ Init_fiddle(void) */ rb_define_const(mFiddle, "SIZEOF_UINTPTR_T", INT2NUM(sizeof(uintptr_t))); + /* Document-const: SIZEOF_CONST_STRING + * + * size of a const char* + */ + rb_define_const(mFiddle, "SIZEOF_CONST_STRING", INT2NUM(sizeof(const char*))); + /* Document-const: RUBY_FREE * * Address of the ruby_xfree() function diff --git a/ext/fiddle/fiddle.h b/ext/fiddle/fiddle.h index 2dddc0b18b..f142229b0c 100644 --- a/ext/fiddle/fiddle.h +++ b/ext/fiddle/fiddle.h @@ -116,6 +116,7 @@ #define TYPE_FLOAT 7 #define TYPE_DOUBLE 8 #define TYPE_VARIADIC 9 +#define TYPE_CONST_STRING 10 #define ALIGN_OF(type) offsetof(struct {char align_c; type align_x;}, align_x) diff --git a/ext/fiddle/function.c b/ext/fiddle/function.c index e96313a512..8771dd3e30 100644 --- a/ext/fiddle/function.c +++ b/ext/fiddle/function.c @@ -207,6 +207,7 @@ function_call(int argc, VALUE argv[], VALUE self) int n_call_args = 0; int i; int i_call; + VALUE converted_args = Qnil; VALUE alloc_buffer = 0; cfunc = rb_iv_get(self, "@ptr"); @@ -313,6 +314,7 @@ function_call(int argc, VALUE argv[], VALUE self) i++, i_call++) { VALUE arg_type; int c_arg_type; + VALUE original_src; VALUE src; arg_type = RARRAY_AREF(arg_types, i_call); c_arg_type = FIX2INT(arg_type); @@ -327,11 +329,22 @@ function_call(int argc, VALUE argv[], VALUE self) } else if (cPointer != CLASS_OF(src)) { src = rb_funcall(cPointer, rb_intern("[]"), 1, src); + if (NIL_P(converted_args)) { + converted_args = rb_ary_new(); + } + rb_ary_push(converted_args, src); } src = rb_Integer(src); } + original_src = src; VALUE2GENERIC(c_arg_type, src, &generic_args[i_call]); + if (src != original_src) { + if (NIL_P(converted_args)) { + converted_args = rb_ary_new(); + } + rb_ary_push(converted_args, src); + } args.values[i_call] = (void *)&generic_args[i_call]; } args.values[i_call] = NULL; diff --git a/ext/fiddle/lib/fiddle/import.rb b/ext/fiddle/lib/fiddle/import.rb index 178ebb8c76..5fcbb1ced8 100644 --- a/ext/fiddle/lib/fiddle/import.rb +++ b/ext/fiddle/lib/fiddle/import.rb @@ -121,6 +121,8 @@ module Fiddle return SIZEOF_DOUBLE when TYPE_VOIDP return SIZEOF_VOIDP + when TYPE_CONST_STRING + return SIZEOF_CONST_STRING else if defined?(TYPE_LONG_LONG) and ty == TYPE_LONG_LONG -- cgit v1.2.3