Ruby 2.7.7p221 (2022-11-24 revision 168ec2b1e5ad0e4688e963d9de019557c78feed9)
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
31static void
32deallocate(void *p)
33{
34 ffi_cif *ptr = p;
35 if (ptr->arg_types) xfree(ptr->arg_types);
36 xfree(ptr);
37}
38
39static size_t
40function_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
48#endif
49
50 return size;
51}
52
54 "fiddle/function",
55 {0, deallocate, function_memsize,},
56};
57
58static VALUE
59allocate(VALUE klass)
60{
61 ffi_cif * cif;
62
63 return TypedData_Make_Struct(klass, ffi_cif, &function_data_type, cif);
64}
65
67rb_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
78static int
79parse_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
90static VALUE
91initialize(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
113 Check_Type(args, T_ARRAY);
114 len = RARRAY_LENINT(args);
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;
153 void **values;
155};
156
157static void *
158nogvl_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
167static VALUE
168function_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))) {
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
224void
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: */
int errno
void ffi_call(ffi_cif *cif, void(*fn)(void), void *rvalue, void **avalue)
Definition: ffi.c:813
@ FFI_DEFAULT_ABI
Definition: ffitarget.h:38
#define NUM2PTR(x)
Definition: conversions.h:37
#define INT2FFI_TYPE(_type)
Definition: conversions.h:32
#define VALUE2GENERIC(_type, _src, _dst)
Definition: conversions.h:31
#define GENERIC2VALUE(_type, _retval)
Definition: conversions.h:33
#define PTR2NUM(x)
Definition: conversions.h:36
#define rb_ary_subseq(ary, beg, len)
Definition: cparse.c:76
struct RIMemo * ptr
Definition: debug.c:65
enum imemo_type types
Definition: debug.c:63
VALUE mFiddle
Definition: fiddle.c:3
#define TYPE_VOIDP
Definition: fiddle.h:108
const rb_data_type_t function_data_type
Definition: function.c:53
#define RB_OBJ_STRING(obj)
Definition: function.c:6
VALUE cFiddleFunction
Definition: function.c:13
VALUE rb_fiddle_new_function(VALUE address, VALUE arg_types, VALUE ret_type)
Definition: function.c:67
#define Check_Max_Args(name, len)
Definition: function.c:17
void Init_fiddle_function(void)
Definition: function.c:225
VALUE rb_define_class_under(VALUE, const char *, VALUE)
Defines a class under the namespace of outer.
Definition: class.c:711
VALUE rb_cObject
Object class.
Definition: ruby.h:2012
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:2671
VALUE rb_eRuntimeError
Definition: error.c:922
VALUE rb_eArgError
Definition: error.c:925
VALUE rb_class_new_instance(int, const VALUE *, VALUE)
Allocates and initializes an instance of klass.
Definition: object.c:1955
VALUE rb_Integer(VALUE)
Equivalent to Kernel#Integer in Ruby.
Definition: object.c:3106
VALUE type(ANYARGS)
ANYARGS-ed function type.
Definition: cxxanyargs.hpp:39
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
size_t ffi_raw_size(ffi_cif *cif)
Definition: raw_api.c:35
#define RARRAY_LEN(a)
void rb_hash_foreach(VALUE, int(*)(VALUE, VALUE, VALUE), VALUE)
#define NULL
#define ALLOCV_END(v)
VALUE rb_const_get(VALUE, ID)
Definition: variable.c:2391
#define RARRAY_LENINT(ary)
#define xfree
#define NIL_P(v)
#define ID2SYM(x)
unsigned long VALUE
__inline__ const void *__restrict__ src
void rb_define_alloc_func(VALUE, rb_alloc_func_t)
uint32_t i
__inline__ const void *__restrict__ size_t len
#define OBJ_FREEZE(x)
#define INT2NUM(x)
#define ALLOCV(v, n)
VALUE rb_iv_set(VALUE, const char *, VALUE)
Definition: variable.c:3318
void rb_define_const(VALUE, const char *, VALUE)
Definition: variable.c:2891
#define NUM2INT(x)
#define TypedData_Get_Struct(obj, type, data_type, sval)
#define PRIsVALUE
#define rb_funcall(recv, mid, argc,...)
#define FIX2INT(x)
#define rb_scan_args(argc, argvp, fmt,...)
#define rb_intern(str)
unsigned int size
long unsigned int size_t
#define T_ARRAY
#define INT2FIX(i)
#define TypedData_Make_Struct(klass, type, data_type, sval)
const VALUE * argv
VALUE rb_iv_get(VALUE, const char *)
Definition: variable.c:3305
#define CLASS_OF(v)
#define Check_Type(v, t)
#define xcalloc
void rb_define_method(VALUE, const char *, VALUE(*)(), int)
#define RARRAY_AREF(a, i)
void rb_ary_store(VALUE, long, VALUE)
Definition: array.c:1079
void(* fn)(void)
Definition: function.c:152
fiddle_generic retval
Definition: function.c:154
void * rb_thread_call_without_gvl(void *(*func)(void *), void *data1, rb_unblock_function_t *ubf, void *data2)
MJIT_STATIC void rb_error_arity(int argc, int min, int max)
@ FFI_STDCALL
Definition: ffitarget.h:110