summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSutou Kouhei <kou@clear-code.com>2020-07-09 20:19:20 +0900
committerSutou Kouhei <kou@cozmixng.org>2020-11-18 09:05:13 +0900
commitae7b53546ca18b56c23f612b6935e98268a07602 (patch)
tree6669206356ba05e4ee4d0e34dd99901ad1ea268c
parent64926d500782cadf578724c3d1e7f59e7aaf200f (diff)
downloadruby-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.c69
-rw-r--r--ext/fiddle/conversions.h17
-rw-r--r--ext/fiddle/fiddle.c12
-rw-r--r--ext/fiddle/fiddle.h1
-rw-r--r--ext/fiddle/function.c13
-rw-r--r--ext/fiddle/lib/fiddle/import.rb2
-rw-r--r--test/fiddle/test_func.rb23
-rw-r--r--test/fiddle/test_import.rb13
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