Ruby  2.7.2p137(2020-10-01revision5445e0435260b449decf2ac16f9d09bae3cafe72)
function.c
Go to the documentation of this file.
1 #include <fiddle.h>
2 #include <ruby/thread.h>
3 
4 #ifdef PRIsVALUE
5 # define RB_OBJ_CLASSNAME(obj) rb_obj_class(obj)
6 # define RB_OBJ_STRING(obj) (obj)
7 #else
8 # define PRIsVALUE "s"
9 # define RB_OBJ_CLASSNAME(obj) rb_obj_classname(obj)
10 # define RB_OBJ_STRING(obj) StringValueCStr(obj)
11 #endif
12 
14 
15 #define MAX_ARGS (SIZE_MAX / (sizeof(void *) + sizeof(fiddle_generic)) - 1)
16 
17 #define Check_Max_Args(name, len) \
18  Check_Max_Args_(name, len, "")
19 #define Check_Max_Args_Long(name, len) \
20  Check_Max_Args_(name, len, "l")
21 #define Check_Max_Args_(name, len, fmt) \
22  if ((size_t)(len) < MAX_ARGS) { \
23  /* OK */ \
24  } \
25  else { \
26  rb_raise(rb_eTypeError, \
27  name" is so large that it can cause integer overflow (%"fmt"d)", \
28  (len)); \
29  }
30 
31 static void
32 deallocate(void *p)
33 {
34  ffi_cif *ptr = p;
35  if (ptr->arg_types) xfree(ptr->arg_types);
36  xfree(ptr);
37 }
38 
39 static size_t
40 function_memsize(const void *p)
41 {
42  /* const */ffi_cif *ptr = (ffi_cif *)p;
43  size_t size = 0;
44 
45  size += sizeof(*ptr);
46 #if !defined(FFI_NO_RAW_API) || !FFI_NO_RAW_API
47  size += ffi_raw_size(ptr);
48 #endif
49 
50  return size;
51 }
52 
54  "fiddle/function",
55  {0, deallocate, function_memsize,},
56 };
57 
58 static VALUE
59 allocate(VALUE klass)
60 {
61  ffi_cif * cif;
62 
64 }
65 
66 VALUE
67 rb_fiddle_new_function(VALUE address, VALUE arg_types, VALUE ret_type)
68 {
69  VALUE argv[3];
70 
71  argv[0] = address;
72  argv[1] = arg_types;
73  argv[2] = ret_type;
74 
76 }
77 
78 static int
79 parse_keyword_arg_i(VALUE key, VALUE value, VALUE self)
80 {
81  if (key == ID2SYM(rb_intern("name"))) {
82  rb_iv_set(self, "@name", value);
83  } else {
84  rb_raise(rb_eArgError, "unknown keyword: %"PRIsVALUE,
86  }
87  return ST_CONTINUE;
88 }
89 
90 static VALUE
91 initialize(int argc, VALUE argv[], VALUE self)
92 {
93  ffi_cif * cif;
94  ffi_type **arg_types, *rtype;
95  ffi_status result;
96  VALUE ptr, args, ret_type, abi, kwds, ary;
97  int i, len;
98  int nabi;
99  void *cfunc;
100 
101  rb_scan_args(argc, argv, "31:", &ptr, &args, &ret_type, &abi, &kwds);
102  rb_iv_set(self, "@closure", ptr);
103 
104  ptr = rb_Integer(ptr);
105  cfunc = NUM2PTR(ptr);
106  PTR2NUM(cfunc);
107  nabi = NIL_P(abi) ? FFI_DEFAULT_ABI : NUM2INT(abi);
108  abi = INT2FIX(nabi);
109  i = NUM2INT(ret_type);
110  rtype = INT2FFI_TYPE(i);
111  ret_type = INT2FIX(i);
112 
115  Check_Max_Args("args", len);
116  ary = rb_ary_subseq(args, 0, len);
117  for (i = 0; i < RARRAY_LEN(args); i++) {
118  VALUE a = RARRAY_AREF(args, i);
119  int type = NUM2INT(a);
120  (void)INT2FFI_TYPE(type); /* raise */
121  if (INT2FIX(type) != a) rb_ary_store(ary, i, INT2FIX(type));
122  }
123  OBJ_FREEZE(ary);
124 
125  rb_iv_set(self, "@ptr", ptr);
126  rb_iv_set(self, "@args", args);
127  rb_iv_set(self, "@return_type", ret_type);
128  rb_iv_set(self, "@abi", abi);
129 
130  if (!NIL_P(kwds)) rb_hash_foreach(kwds, parse_keyword_arg_i, self);
131 
132  TypedData_Get_Struct(self, ffi_cif, &function_data_type, cif);
133 
134  arg_types = xcalloc(len + 1, sizeof(ffi_type *));
135 
136  for (i = 0; i < RARRAY_LEN(args); i++) {
137  int type = NUM2INT(RARRAY_AREF(args, i));
138  arg_types[i] = INT2FFI_TYPE(type);
139  }
140  arg_types[len] = NULL;
141 
142  result = ffi_prep_cif(cif, nabi, len, rtype, arg_types);
143 
144  if (result)
145  rb_raise(rb_eRuntimeError, "error creating CIF %d", result);
146 
147  return self;
148 }
149 
151  ffi_cif *cif;
152  void (*fn)(void);
153  void **values;
155 };
156 
157 static void *
158 nogvl_ffi_call(void *ptr)
159 {
160  struct nogvl_ffi_call_args *args = ptr;
161 
162  ffi_call(args->cif, args->fn, &args->retval, args->values);
163 
164  return NULL;
165 }
166 
167 static VALUE
168 function_call(int argc, VALUE argv[], VALUE self)
169 {
170  struct nogvl_ffi_call_args args = { 0 };
171  fiddle_generic *generic_args;
172  VALUE cfunc, types, cPointer;
173  int i;
174  VALUE alloc_buffer = 0;
175 
176  cfunc = rb_iv_get(self, "@ptr");
177  types = rb_iv_get(self, "@args");
178  cPointer = rb_const_get(mFiddle, rb_intern("Pointer"));
179 
180  Check_Max_Args("number of arguments", argc);
181  if (argc != (i = RARRAY_LENINT(types))) {
182  rb_error_arity(argc, i, i);
183  }
184 
185  TypedData_Get_Struct(self, ffi_cif, &function_data_type, args.cif);
186 
187  generic_args = ALLOCV(alloc_buffer,
188  (size_t)(argc + 1) * sizeof(void *) + (size_t)argc * sizeof(fiddle_generic));
189  args.values = (void **)((char *)generic_args +
190  (size_t)argc * sizeof(fiddle_generic));
191 
192  for (i = 0; i < argc; i++) {
194  VALUE src = argv[i];
195  int argtype = FIX2INT(type);
196 
197  if (argtype == TYPE_VOIDP) {
198  if(NIL_P(src)) {
199  src = INT2FIX(0);
200  } else if(cPointer != CLASS_OF(src)) {
201  src = rb_funcall(cPointer, rb_intern("[]"), 1, src);
202  }
203  src = rb_Integer(src);
204  }
205 
206  VALUE2GENERIC(argtype, src, &generic_args[i]);
207  args.values[i] = (void *)&generic_args[i];
208  }
209  args.values[argc] = NULL;
210  args.fn = (void(*)(void))NUM2PTR(cfunc);
211 
212  (void)rb_thread_call_without_gvl(nogvl_ffi_call, &args, 0, 0);
213 
214  rb_funcall(mFiddle, rb_intern("last_error="), 1, INT2NUM(errno));
215 #if defined(_WIN32)
216  rb_funcall(mFiddle, rb_intern("win32_last_error="), 1, INT2NUM(errno));
217 #endif
218 
219  ALLOCV_END(alloc_buffer);
220 
221  return GENERIC2VALUE(rb_iv_get(self, "@return_type"), args.retval);
222 }
223 
224 void
226 {
227  /*
228  * Document-class: Fiddle::Function
229  *
230  * == Description
231  *
232  * A representation of a C function
233  *
234  * == Examples
235  *
236  * === 'strcpy'
237  *
238  * @libc = Fiddle.dlopen "/lib/libc.so.6"
239  * #=> #<Fiddle::Handle:0x00000001d7a8d8>
240  * f = Fiddle::Function.new(
241  * @libc['strcpy'],
242  * [Fiddle::TYPE_VOIDP, Fiddle::TYPE_VOIDP],
243  * Fiddle::TYPE_VOIDP)
244  * #=> #<Fiddle::Function:0x00000001d8ee00>
245  * buff = "000"
246  * #=> "000"
247  * str = f.call(buff, "123")
248  * #=> #<Fiddle::Pointer:0x00000001d0c380 ptr=0x000000018a21b8 size=0 free=0x00000000000000>
249  * str.to_s
250  * => "123"
251  *
252  * === ABI check
253  *
254  * @libc = Fiddle.dlopen "/lib/libc.so.6"
255  * #=> #<Fiddle::Handle:0x00000001d7a8d8>
256  * f = Fiddle::Function.new(@libc['strcpy'], [TYPE_VOIDP, TYPE_VOIDP], TYPE_VOIDP)
257  * #=> #<Fiddle::Function:0x00000001d8ee00>
258  * f.abi == Fiddle::Function::DEFAULT
259  * #=> true
260  */
262 
263  /*
264  * Document-const: DEFAULT
265  *
266  * Default ABI
267  *
268  */
270 
271 #ifdef HAVE_CONST_FFI_STDCALL
272  /*
273  * Document-const: STDCALL
274  *
275  * FFI implementation of WIN32 stdcall convention
276  *
277  */
279 #endif
280 
282 
283  /*
284  * Document-method: call
285  *
286  * Calls the constructed Function, with +args+.
287  * Caller must ensure the underlying function is called in a
288  * thread-safe manner if running in a multi-threaded process.
289  *
290  * For an example see Fiddle::Function
291  *
292  */
293  rb_define_method(cFiddleFunction, "call", function_call, -1);
294 
295  /*
296  * Document-method: new
297  * call-seq: new(ptr, args, ret_type, abi = DEFAULT)
298  *
299  * Constructs a Function object.
300  * * +ptr+ is a referenced function, of a Fiddle::Handle
301  * * +args+ is an Array of arguments, passed to the +ptr+ function
302  * * +ret_type+ is the return type of the function
303  * * +abi+ is the ABI of the function
304  *
305  */
306  rb_define_method(cFiddleFunction, "initialize", initialize, -1);
307 }
308 /* vim: set noet sws=4 sw=4: */
TYPE_VOIDP
#define TYPE_VOIDP
Definition: fiddle.h:108
TypedData_Make_Struct
#define TypedData_Make_Struct(klass, type, data_type, sval)
Definition: ruby.h:1244
Check_Type
#define Check_Type(v, t)
Definition: ruby.h:595
xcalloc
#define xcalloc
Definition: defines.h:213
FIX2INT
#define FIX2INT(x)
Definition: ruby.h:717
mFiddle
VALUE mFiddle
Definition: fiddle.c:3
GENERIC2VALUE
#define GENERIC2VALUE(_type, _retval)
Definition: conversions.h:33
callback_args::cif
ffi_cif * cif
Definition: closure.c:58
VALUE2GENERIC
#define VALUE2GENERIC(_type, _src, _dst)
Definition: conversions.h:31
INT2FIX
#define INT2FIX(i)
Definition: ruby.h:263
FFI_STDCALL
@ FFI_STDCALL
Definition: ffitarget.h:110
i
uint32_t i
Definition: rb_mjit_min_header-2.7.2.h:5460
fiddle.h
VALUE
unsigned long VALUE
Definition: ruby.h:102
rb_eArgError
VALUE rb_eArgError
Definition: error.c:925
rb_intern
#define rb_intern(str)
rb_ary_store
void rb_ary_store(VALUE ary, long idx, VALUE val)
Definition: array.c:1079
rb_fiddle_new_function
VALUE rb_fiddle_new_function(VALUE address, VALUE arg_types, VALUE ret_type)
Definition: function.c:67
rb_define_method
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Definition: class.c:1551
INT2NUM
#define INT2NUM(x)
Definition: ruby.h:1609
cFiddleFunction
VALUE cFiddleFunction
Definition: function.c:13
ptr
struct RIMemo * ptr
Definition: debug.c:65
rb_Integer
VALUE rb_Integer(VALUE)
Equivalent to Kernel#Integer in Ruby.
Definition: object.c:3106
nogvl_ffi_call_args::values
void ** values
Definition: function.c:153
NULL
#define NULL
Definition: _sdbm.c:101
PRIsVALUE
#define PRIsVALUE
Definition: ruby.h:166
fiddle_generic
Definition: conversions.h:7
ID2SYM
#define ID2SYM(x)
Definition: ruby.h:414
OBJ_FREEZE
#define OBJ_FREEZE(x)
Definition: ruby.h:1377
RARRAY_LENINT
#define RARRAY_LENINT(ary)
Definition: ruby.h:1071
void
void
Definition: rb_mjit_min_header-2.7.2.h:13241
rb_raise
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:2671
nogvl_ffi_call_args::fn
void(* fn)(void)
Definition: function.c:152
klass
VALUE klass
Definition: rb_mjit_min_header-2.7.2.h:13222
ALLOCV_END
#define ALLOCV_END(v)
Definition: ruby.h:1750
rb_iv_get
VALUE rb_iv_get(VALUE, const char *)
Definition: variable.c:3305
nogvl_ffi_call_args::retval
fiddle_generic retval
Definition: function.c:154
INT2FFI_TYPE
#define INT2FFI_TYPE(_type)
Definition: conversions.h:32
RARRAY_AREF
#define RARRAY_AREF(a, i)
Definition: psych_emitter.c:7
NUM2PTR
#define NUM2PTR(x)
Definition: conversions.h:37
rb_ary_subseq
#define rb_ary_subseq(ary, beg, len)
Definition: cparse.c:76
rb_eRuntimeError
VALUE rb_eRuntimeError
Definition: error.c:922
rb_thread_call_without_gvl
void * rb_thread_call_without_gvl(void *(*func)(void *), void *data1, rb_unblock_function_t *ubf, void *data2)
size
int size
Definition: encoding.c:58
rb_hash_foreach
void rb_hash_foreach(VALUE hash, rb_foreach_func *func, VALUE farg)
Definition: hash.c:1483
rb_error_arity
MJIT_STATIC void rb_error_arity(int argc, int min, int max)
Definition: vm_insnhelper.c:387
FFI_DEFAULT_ABI
@ FFI_DEFAULT_ABI
Definition: ffitarget.h:38
ffi_raw_size
size_t ffi_raw_size(ffi_cif *cif)
Definition: raw_api.c:35
key
key
Definition: openssl_missing.h:181
rb_scan_args
#define rb_scan_args(argc, argvp, fmt,...)
Definition: rb_mjit_min_header-2.7.2.h:6368
RB_OBJ_STRING
#define RB_OBJ_STRING(obj)
Definition: function.c:6
CLASS_OF
#define CLASS_OF(v)
Definition: ruby.h:484
RARRAY_LEN
#define RARRAY_LEN(a)
Definition: ruby.h:1070
nogvl_ffi_call_args
Definition: function.c:150
rb_cObject
RUBY_EXTERN VALUE rb_cObject
Definition: ruby.h:2010
TypedData_Get_Struct
#define TypedData_Get_Struct(obj, type, data_type, sval)
Definition: ruby.h:1252
T_ARRAY
#define T_ARRAY
Definition: ruby.h:530
argv
char ** argv
Definition: ruby.c:223
ST_CONTINUE
@ ST_CONTINUE
Definition: st.h:99
src
__inline__ const void *__restrict src
Definition: rb_mjit_min_header-2.7.2.h:2842
types
enum imemo_type types
Definition: debug.c:63
Init_fiddle_function
void Init_fiddle_function(void)
Definition: function.c:225
NIL_P
#define NIL_P(v)
Definition: ruby.h:482
rb_funcall
#define rb_funcall(recv, mid, argc,...)
Definition: rb_mjit_min_header-2.7.2.h:6581
ffi_prep_cif
ffi_status ffi_prep_cif(ffi_cif *cif, ffi_abi abi, unsigned int nargs, ffi_type *rtype, ffi_type **atypes)
Definition: prep_cif.c:226
argc
int argc
Definition: ruby.c:222
PTR2NUM
#define PTR2NUM(x)
Definition: conversions.h:36
rb_define_const
void rb_define_const(VALUE, const char *, VALUE)
Definition: variable.c:2891
rb_data_type_struct
Definition: ruby.h:1148
xfree
#define xfree
Definition: defines.h:216
size_t
unsigned int size_t
Definition: rb_mjit_min_header-2.7.2.h:663
Check_Max_Args
#define Check_Max_Args(name, len)
Definition: function.c:17
nogvl_ffi_call_args::cif
ffi_cif * cif
Definition: function.c:151
errno
int errno
len
uint8_t len
Definition: escape.c:17
ffi_call
void ffi_call(ffi_cif *cif, void(*fn)(void), void *rvalue, void **avalue)
Definition: ffi.c:813
rb_class_new_instance
VALUE rb_class_new_instance(int, const VALUE *, VALUE)
Allocates and initializes an instance of klass.
Definition: object.c:1955
rb_define_class_under
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition: class.c:698
callback_args::args
void ** args
Definition: closure.c:60
NUM2INT
#define NUM2INT(x)
Definition: ruby.h:715
thread.h
ALLOCV
#define ALLOCV(v, n)
Definition: ruby.h:1748
function_data_type
const rb_data_type_t function_data_type
Definition: function.c:53
rb_define_alloc_func
void rb_define_alloc_func(VALUE, rb_alloc_func_t)
ruby::backward::cxxanyargs::type
VALUE type(ANYARGS)
ANYARGS-ed function type.
Definition: cxxanyargs.hpp:39
rb_iv_set
VALUE rb_iv_set(VALUE, const char *, VALUE)
Definition: variable.c:3318
rb_const_get
VALUE rb_const_get(VALUE, ID)
Definition: variable.c:2391