diff options
author | Sutou Kouhei <kou@clear-code.com> | 2020-07-09 20:19:20 +0900 |
---|---|---|
committer | Sutou Kouhei <kou@cozmixng.org> | 2020-11-18 09:05:13 +0900 |
commit | ae7b53546ca18b56c23f612b6935e98268a07602 (patch) | |
tree | 6669206356ba05e4ee4d0e34dd99901ad1ea268c | |
parent | 64926d500782cadf578724c3d1e7f59e7aaf200f (diff) | |
download | ruby-ae7b53546ca18b56c23f612b6935e98268a07602.tar.gz |
[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
-rw-r--r-- | ext/fiddle/conversions.c | 69 | ||||
-rw-r--r-- | ext/fiddle/conversions.h | 17 | ||||
-rw-r--r-- | ext/fiddle/fiddle.c | 12 | ||||
-rw-r--r-- | ext/fiddle/fiddle.h | 1 | ||||
-rw-r--r-- | ext/fiddle/function.c | 13 | ||||
-rw-r--r-- | ext/fiddle/lib/fiddle/import.rb | 2 | ||||
-rw-r--r-- | test/fiddle/test_func.rb | 23 | ||||
-rw-r--r-- | test/fiddle/test_import.rb | 13 |
8 files changed, 121 insertions, 29 deletions
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 <fiddle.h> 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 diff --git a/test/fiddle/test_func.rb b/test/fiddle/test_func.rb index 29a0a455f1..ca9d4ccb34 100644 --- a/test/fiddle/test_func.rb +++ b/test/fiddle/test_func.rb @@ -98,7 +98,7 @@ module Fiddle [ TYPE_VOIDP, TYPE_SIZE_T, - TYPE_VOIDP, + TYPE_CONST_STRING, TYPE_VARIADIC, ], TYPE_INT) @@ -107,20 +107,31 @@ module Fiddle written = snprintf.call(output, output.size, - "int: %d, string: %.*s\n", + "int: %d, string: %.*s, const string: %s\n", TYPE_INT, -29, TYPE_INT, 4, - TYPE_VOIDP, "Hello") - assert_equal("int: -29, string: Hell\n", + TYPE_VOIDP, "Hello", + TYPE_CONST_STRING, "World") + assert_equal("int: -29, string: Hell, const string: World\n", output_buffer[0, written]) + string_like_class = Class.new do + def initialize(string) + @string = string + end + + def to_str + @string + end + end written = snprintf.call(output, output.size, - "string: %.*s, uint: %u\n", + "string: %.*s, const string: %s, uint: %u\n", TYPE_INT, 2, TYPE_VOIDP, "Hello", + TYPE_CONST_STRING, string_like_class.new("World"), TYPE_INT, 29) - assert_equal("string: He, uint: 29\n", + assert_equal("string: He, const string: World, uint: 29\n", output_buffer[0, written]) end end diff --git a/test/fiddle/test_import.rb b/test/fiddle/test_import.rb index c56d81c351..4afd8e5562 100644 --- a/test/fiddle/test_import.rb +++ b/test/fiddle/test_import.rb @@ -112,10 +112,17 @@ module Fiddle Fiddle.constants.grep(/\ATYPE_(?!VOID|VARIADIC\z)(.*)/) do type = $& - size = Fiddle.const_get("SIZEOF_#{$1}") - name = $1.sub(/P\z/,"*").gsub(/_(?!T\z)/, " ").downcase + const_type_name = $1 + size = Fiddle.const_get("SIZEOF_#{const_type_name}") + if const_type_name == "CONST_STRING" + name = "const_string" + type_name = "const char*" + else + name = $1.sub(/P\z/,"*").gsub(/_(?!T\z)/, " ").downcase + type_name = name + end define_method("test_sizeof_#{name}") do - assert_equal(size, Fiddle::Importer.sizeof(name), type) + assert_equal(size, Fiddle::Importer.sizeof(type_name), type) end end |