Ruby  2.0.0p648(2015-12-16revision53162)
function.c
Go to the documentation of this file.
1 #include <fiddle.h>
2 
3 #ifdef PRIsVALUE
4 # define RB_OBJ_CLASSNAME(obj) rb_obj_class(obj)
5 # define RB_OBJ_STRING(obj) (obj)
6 #else
7 # define PRIsVALUE "s"
8 # define RB_OBJ_CLASSNAME(obj) rb_obj_classname(obj)
9 # define RB_OBJ_STRING(obj) StringValueCStr(obj)
10 #endif
11 
13 
14 #define MAX_ARGS (SIZE_MAX / (sizeof(void *) + sizeof(fiddle_generic)) - 1)
15 
16 #define Check_Max_Args(name, len) \
17  Check_Max_Args_(name, len, "")
18 #define Check_Max_Args_Long(name, len) \
19  Check_Max_Args_(name, len, "l")
20 #define Check_Max_Args_(name, len, fmt) \
21  if ((size_t)(len) < MAX_ARGS) { \
22  /* OK */ \
23  } \
24  else { \
25  rb_raise(rb_eTypeError, \
26  name" is so large that it can cause integer overflow (%"fmt"d)", \
27  (len)); \
28  }
29 
30 static void
31 deallocate(void *p)
32 {
33  ffi_cif *ptr = p;
34  if (ptr->arg_types) xfree(ptr->arg_types);
35  xfree(ptr);
36 }
37 
38 static size_t
39 function_memsize(const void *p)
40 {
41  /* const */ffi_cif *ptr = (ffi_cif *)p;
42  size_t size = 0;
43 
44  if (ptr) {
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",
56 };
57 
58 static VALUE
60 {
61  ffi_cif * cif;
62 
63  return TypedData_Make_Struct(klass, ffi_cif, &function_data_type, cif);
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 
75  return rb_class_new_instance(3, argv, cFiddleFunction);
76 }
77 
78 static int
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,
85  RB_OBJ_STRING(key));
86  }
87  return ST_CONTINUE;
88 }
89 
90 static VALUE
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  ptr = rb_Integer(ptr);
103  cfunc = NUM2PTR(ptr);
104  PTR2NUM(cfunc);
105  nabi = NIL_P(abi) ? FFI_DEFAULT_ABI : NUM2INT(abi);
106  abi = INT2FIX(nabi);
107  i = NUM2INT(ret_type);
108  rtype = INT2FFI_TYPE(i);
109  ret_type = INT2FIX(i);
110 
111  Check_Type(args, T_ARRAY);
112  len = RARRAY_LENINT(args);
113  Check_Max_Args_Long("args", len);
114  ary = rb_ary_subseq(args, 0, len);
115  for (i = 0; i < RARRAY_LEN(args); i++) {
116  VALUE a = RARRAY_PTR(args)[i];
117  int type = NUM2INT(a);
118  (void)INT2FFI_TYPE(type); /* raise */
119  if (INT2FIX(type) != a) rb_ary_store(ary, i, INT2FIX(type));
120  }
121  OBJ_FREEZE(ary);
122 
123  rb_iv_set(self, "@ptr", ptr);
124  rb_iv_set(self, "@args", args);
125  rb_iv_set(self, "@return_type", ret_type);
126  rb_iv_set(self, "@abi", abi);
127 
128  if (!NIL_P(kwds)) rb_hash_foreach(kwds, parse_keyword_arg_i, self);
129 
130  TypedData_Get_Struct(self, ffi_cif, &function_data_type, cif);
131 
132  arg_types = xcalloc(len + 1, sizeof(ffi_type *));
133 
134  for (i = 0; i < RARRAY_LEN(args); i++) {
135  int type = NUM2INT(RARRAY_PTR(args)[i]);
136  arg_types[i] = INT2FFI_TYPE(type);
137  }
138  arg_types[len] = NULL;
139 
140  result = ffi_prep_cif(cif, nabi, len, rtype, arg_types);
141 
142  if (result)
143  rb_raise(rb_eRuntimeError, "error creating CIF %d", result);
144 
145  return self;
146 }
147 
148 static VALUE
150 {
151  ffi_cif * cif;
152  fiddle_generic retval;
153  fiddle_generic *generic_args;
154  void **values;
155  VALUE cfunc, types, cPointer;
156  int i;
157  VALUE alloc_buffer = 0;
158 
159  cfunc = rb_iv_get(self, "@ptr");
160  types = rb_iv_get(self, "@args");
161  cPointer = rb_const_get(mFiddle, rb_intern("Pointer"));
162 
163  Check_Max_Args("number of arguments", argc);
164  if(argc != RARRAY_LENINT(types)) {
165  rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)",
166  argc, RARRAY_LENINT(types));
167  }
168 
169  TypedData_Get_Struct(self, ffi_cif, &function_data_type, cif);
170 
171  if (rb_safe_level() >= 1) {
172  for (i = 0; i < argc; i++) {
173  VALUE src = argv[i];
174  if (OBJ_TAINTED(src)) {
175  rb_raise(rb_eSecurityError, "tainted parameter not allowed");
176  }
177  }
178  }
179 
180  generic_args = ALLOCV(alloc_buffer,
181  (size_t)(argc + 1) * sizeof(void *) + (size_t)argc * sizeof(fiddle_generic));
182  values = (void **)((char *)generic_args + (size_t)argc * sizeof(fiddle_generic));
183 
184  for (i = 0; i < argc; i++) {
185  VALUE type = RARRAY_PTR(types)[i];
186  VALUE src = argv[i];
187  int argtype = FIX2INT(type);
188 
189  if (argtype == TYPE_VOIDP) {
190  if(NIL_P(src)) {
191  src = INT2NUM(0);
192  } else if(cPointer != CLASS_OF(src)) {
193  src = rb_funcall(cPointer, rb_intern("[]"), 1, src);
194  }
195  src = rb_Integer(src);
196  }
197 
198  VALUE2GENERIC(argtype, src, &generic_args[i]);
199  values[i] = (void *)&generic_args[i];
200  }
201  values[argc] = NULL;
202 
203  ffi_call(cif, NUM2PTR(cfunc), &retval, values);
204 
205  rb_funcall(mFiddle, rb_intern("last_error="), 1, INT2NUM(errno));
206 #if defined(_WIN32)
207  rb_funcall(mFiddle, rb_intern("win32_last_error="), 1, INT2NUM(errno));
208 #endif
209 
210  ALLOCV_END(alloc_buffer);
211 
212  return GENERIC2VALUE(rb_iv_get(self, "@return_type"), retval);
213 }
214 
215 void
217 {
218  /*
219  * Document-class: Fiddle::Function
220  *
221  * == Description
222  *
223  * A representation of a C function
224  *
225  * == Examples
226  *
227  * === 'strcpy'
228  *
229  * @libc = Fiddle.dlopen "/lib/libc.so.6"
230  * #=> #<Fiddle::Handle:0x00000001d7a8d8>
231  * f = Fiddle::Function.new(
232  * @libc['strcpy'],
233  * [Fiddle::TYPE_VOIDP, Fiddle::TYPE_VOIDP],
234  * Fiddle::TYPE_VOIDP)
235  * #=> #<Fiddle::Function:0x00000001d8ee00>
236  * buff = "000"
237  * #=> "000"
238  * str = f.call(buff, "123")
239  * #=> #<Fiddle::Pointer:0x00000001d0c380 ptr=0x000000018a21b8 size=0 free=0x00000000000000>
240  * str.to_s
241  * => "123"
242  *
243  * === ABI check
244  *
245  * @libc = DL.dlopen "/lib/libc.so.6"
246  * #=> #<Fiddle::Handle:0x00000001d7a8d8>
247  * f = Fiddle::Function.new(@libc['strcpy'], [TYPE_VOIDP, TYPE_VOIDP], TYPE_VOIDP)
248  * #=> #<Fiddle::Function:0x00000001d8ee00>
249  * f.abi == Fiddle::Function::DEFAULT
250  * #=> true
251  */
253 
254  /*
255  * Document-const: DEFAULT
256  *
257  * Default ABI
258  *
259  */
260  rb_define_const(cFiddleFunction, "DEFAULT", INT2NUM(FFI_DEFAULT_ABI));
261 
262 #ifdef HAVE_CONST_FFI_STDCALL
263  /*
264  * Document-const: STDCALL
265  *
266  * FFI implementation of WIN32 stdcall convention
267  *
268  */
269  rb_define_const(cFiddleFunction, "STDCALL", INT2NUM(FFI_STDCALL));
270 #endif
271 
273 
274  /*
275  * Document-method: call
276  *
277  * Calls the constructed Function, with +args+
278  *
279  * For an example see Fiddle::Function
280  *
281  */
283 
284  /*
285  * Document-method: new
286  * call-seq: new(ptr, args, ret_type, abi = DEFAULT)
287  *
288  * Constructs a Function object.
289  * * +ptr+ is a referenced function, of a Fiddle::Handle
290  * * +args+ is an Array of arguments, passed to the +ptr+ function
291  * * +ret_type+ is the return type of the function
292  * * +abi+ is the ABI of the function
293  *
294  */
295  rb_define_method(cFiddleFunction, "initialize", initialize, -1);
296 }
297 /* vim: set noet sws=4 sw=4: */
#define VALUE2GENERIC(_type, _src, _dst)
Definition: conversions.h:31
#define TYPE_VOIDP
Definition: fiddle.h:113
#define RARRAY_LEN(a)
Definition: ruby.h:899
VALUE mFiddle
Definition: fiddle.c:3
#define INT2NUM(x)
Definition: ruby.h:1178
int i
Definition: win32ole.c:784
#define NUM2INT(x)
Definition: ruby.h:622
#define CLASS_OF(v)
Definition: ruby.h:448
VALUE rb_ary_subseq(VALUE ary, long beg, long len)
Definition: array.c:1097
#define TypedData_Get_Struct(obj, type, data_type, sval)
Definition: ruby.h:1030
static VALUE initialize(int argc, VALUE argv[], VALUE self)
Definition: function.c:91
VALUE rb_funcall(VALUE, ID, int,...)
Calls a method.
Definition: vm_eval.c:773
#define NUM2PTR(x)
Definition: dl.h:169
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition: class.c:534
#define Check_Type(v, t)
Definition: ruby.h:539
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:1788
void rb_define_alloc_func(VALUE, rb_alloc_func_t)
VALUE rb_eSecurityError
Definition: error.c:525
#define Check_Max_Args_Long(name, len)
Definition: function.c:18
#define T_ARRAY
Definition: ruby.h:492
static void deallocate(void *p)
Definition: function.c:31
#define OBJ_TAINTED(x)
Definition: ruby.h:1153
Win32OLEIDispatch * p
Definition: win32ole.c:786
void rb_hash_foreach(VALUE hash, int(*func)(ANYARGS), VALUE farg)
Definition: hash.c:200
int args
Definition: win32ole.c:785
VALUE rb_class_new_instance(int, VALUE *, VALUE)
Definition: object.c:1794
RUBY_EXTERN VALUE rb_cObject
Definition: ruby.h:1426
VALUE rb_eRuntimeError
Definition: error.c:515
#define RB_OBJ_STRING(obj)
Definition: function.c:5
VALUE rb_iv_get(VALUE, const char *)
Definition: variable.c:2586
static VALUE function_call(int argc, VALUE argv[], VALUE self)
Definition: function.c:149
#define NIL_P(v)
Definition: ruby.h:446
#define PTR2NUM(x)
Definition: dl.h:168
void rb_define_const(VALUE, const char *, VALUE)
Definition: variable.c:2204
void rb_ary_store(VALUE ary, long idx, VALUE val)
Definition: array.c:719
VALUE cFiddleFunction
Definition: function.c:12
static int parse_keyword_arg_i(VALUE key, VALUE value, VALUE self)
Definition: function.c:79
int argc
Definition: ruby.c:130
VALUE rb_Integer(VALUE)
Definition: object.c:2539
#define OBJ_FREEZE(x)
Definition: ruby.h:1164
#define INT2FFI_TYPE(_type)
Definition: conversions.h:32
#define ALLOCV_END(v)
Definition: ruby.h:1239
VALUE rb_const_get(VALUE, ID)
Definition: variable.c:1876
int errno
VALUE rb_iv_set(VALUE, const char *, VALUE)
Definition: variable.c:2594
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Definition: class.c:1570
#define PRIsVALUE
Definition: ruby.h:147
#define Check_Max_Args(name, len)
Definition: function.c:16
int type
Definition: tcltklib.c:111
unsigned long VALUE
Definition: ruby.h:104
static VALUE allocate(VALUE klass)
Definition: function.c:59
static VALUE result
Definition: nkf.c:40
#define FIX2INT(x)
Definition: ruby.h:624
#define RARRAY_LENINT(ary)
Definition: ruby.h:908
void xfree(void *)
VALUE rb_fiddle_new_function(VALUE address, VALUE arg_types, VALUE ret_type)
Definition: function.c:67
int size
Definition: encoding.c:52
#define INT2FIX(i)
Definition: ruby.h:241
#define RARRAY_PTR(a)
Definition: ruby.h:904
uint8_t key[16]
Definition: random.c:1370
#define ALLOCV(v, n)
Definition: ruby.h:1236
const rb_data_type_t function_data_type
Definition: function.c:53
#define TypedData_Make_Struct(klass, type, data_type, sval)
Definition: ruby.h:1019
#define GENERIC2VALUE(_type, _retval)
Definition: conversions.h:33
#define rb_safe_level()
Definition: tcltklib.c:94
#define ID2SYM(x)
Definition: ruby.h:363
void Init_fiddle_function(void)
Definition: function.c:216
#define rb_intern(str)
#define NULL
Definition: _sdbm.c:102
static size_t function_memsize(const void *p)
Definition: function.c:39
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Definition: class.c:1344
VALUE rb_eArgError
Definition: error.c:517
char ** argv
Definition: ruby.c:131
#define xcalloc
Definition: defines.h:66