In Files

  • fiddle/closure.c
  • fiddle/lib/fiddle/function.rb

Parent

Methods

Class/Module Index [+]

Quicksearch

Fiddle::Function

Description

A representation of a C function

Examples

'strcpy'

@libc = DL.dlopen "/lib/libc.so.6"
=> #<DL::Handle:0x00000001d7a8d8>
f = Fiddle::Function.new(@libc['strcpy'], [TYPE_VOIDP, TYPE_VOIDP], TYPE_VOIDP)
=> #<Fiddle::Function:0x00000001d8ee00>
buff = "000"
=> "000"
str = f.call(buff, "123")
=> #<DL::CPtr:0x00000001d0c380 ptr=0x000000018a21b8 size=0 free=0x00000000000000>
str.to_s
=> "123"

ABI check

@libc = DL.dlopen "/lib/libc.so.6"
=> #<DL::Handle:0x00000001d7a8d8>
f = Fiddle::Function.new(@libc['strcpy'], [TYPE_VOIDP, TYPE_VOIDP], TYPE_VOIDP)
=> #<Fiddle::Function:0x00000001d8ee00>
f.abi == Fiddle::Function::DEFAULT
=> true

Constants

DEFAULT

DEFAULT

Default ABI

STDCALL

STDCALL

FFI implementation of WIN32 stdcall convention

Attributes

abi[R]

The ABI of the Function.

Public Class Methods

new(ptr, args, ret_type, abi = DEFAULT) click to toggle source

Constructs a Function object.

  • ptr is a referenced function, of a DL::Handle

  • args is an Array of arguments, passed to the ptr function

  • ret_type is the return type of the function

  • abi is the ABI of the function

 
               static VALUE
initialize(int argc, VALUE argv[], VALUE self)
{
    ffi_cif * cif;
    ffi_type **arg_types;
    ffi_status result;
    VALUE ptr, args, ret_type, abi;
    int i;

    rb_scan_args(argc, argv, "31", &ptr, &args, &ret_type, &abi);
    if(NIL_P(abi)) abi = INT2NUM(FFI_DEFAULT_ABI);

    Check_Type(args, T_ARRAY);

    rb_iv_set(self, "@ptr", ptr);
    rb_iv_set(self, "@args", args);
    rb_iv_set(self, "@return_type", ret_type);
    rb_iv_set(self, "@abi", abi);

    TypedData_Get_Struct(self, ffi_cif, &function_data_type, cif);

    arg_types = xcalloc(RARRAY_LEN(args) + 1, sizeof(ffi_type *));

    for (i = 0; i < RARRAY_LEN(args); i++) {
        int type = NUM2INT(RARRAY_PTR(args)[i]);
        arg_types[i] = INT2FFI_TYPE(type);
    }
    arg_types[RARRAY_LEN(args)] = NULL;

    result = ffi_prep_cif (
            cif,
            NUM2INT(abi),
            RARRAY_LENINT(args),
            INT2FFI_TYPE(NUM2INT(ret_type)),
            arg_types);

    if (result)
        rb_raise(rb_eRuntimeError, "error creating CIF %d", result);

    return self;
}
            

Public Instance Methods

call(*args) click to toggle source

Calls the constructed Function, with args

For an example see Fiddle::Function

 
               static VALUE
function_call(int argc, VALUE argv[], VALUE self)
{
    ffi_cif * cif;
    fiddle_generic retval;
    fiddle_generic *generic_args;
    void **values;
    VALUE cfunc, types, cPointer;
    int i;

    cfunc    = rb_iv_get(self, "@ptr");
    types    = rb_iv_get(self, "@args");
    cPointer = rb_const_get(mFiddle, rb_intern("Pointer"));

    if(argc != RARRAY_LENINT(types)) {
        rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)",
                argc, RARRAY_LENINT(types));
    }

    TypedData_Get_Struct(self, ffi_cif, &function_data_type, cif);

    if (rb_safe_level() >= 1) {
        for (i = 0; i < argc; i++) {
            VALUE src = argv[i];
            if (OBJ_TAINTED(src)) {
                rb_raise(rb_eSecurityError, "tainted parameter not allowed");
            }
        }
    }

    values = xcalloc((size_t)argc + 1, (size_t)sizeof(void *));
    generic_args = xcalloc((size_t)argc, (size_t)sizeof(fiddle_generic));

    for (i = 0; i < argc; i++) {
        VALUE type = RARRAY_PTR(types)[i];
        VALUE src = argv[i];

        if(NUM2INT(type) == TYPE_VOIDP) {
            if(NIL_P(src)) {
                src = INT2NUM(0);
            } else if(cPointer != CLASS_OF(src)) {
                src = rb_funcall(cPointer, rb_intern("[]"), 1, src);
            }
            src = rb_Integer(src);
        }

        VALUE2GENERIC(NUM2INT(type), src, &generic_args[i]);
        values[i] = (void *)&generic_args[i];
    }
    values[argc] = NULL;

    ffi_call(cif, NUM2PTR(rb_Integer(cfunc)), &retval, values);

    rb_funcall(mFiddle, rb_intern("last_error="), 1, INT2NUM(errno));
#if defined(_WIN32)
    rb_funcall(mFiddle, rb_intern("win32_last_error="), 1, INT2NUM(errno));
#endif

    xfree(values);
    xfree(generic_args);

    return GENERIC2VALUE(rb_iv_get(self, "@return_type"), retval);
}