Class: Fiddle::Function

Inherits:
Object
  • Object
show all
Defined in:
function.c,
lib/fiddle/function.rb,
lib/fiddle/ffi_backend.rb,
function.c

Overview

Description

A representation of a C function

Examples

‘strcpy’

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

ABI check

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

Constant Summary collapse

DEFAULT =

Default ABI

INT2NUM(FFI_DEFAULT_ABI)
STDCALL =

FFI implementation of WIN32 stdcall convention

INT2NUM(FFI_STDCALL)

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#new(ptr) ⇒ Object #argsObject #ret_typeObject #abi=(DEFAULT) ⇒ Object #nameObject #need_gvlObject

Constructs a Function object.

  • ptr is a referenced function, of a Fiddle::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

  • name is the name of the function

  • need_gvl is whether GVL is needed to call the function



126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'function.c', line 126

def initialize(ptr, args, return_type, abi = DEFAULT, kwargs = nil)
  if kwargs.nil?
    if abi.kind_of? Hash
      kwargs = abi
      abi = DEFAULT
    end
  end
  @name = kwargs[:name] if kwargs.kind_of? Hash
  @ptr, @args, @return_type, @abi = ptr, args, return_type, abi
  raise TypeError.new "invalid argument types" unless args.is_a?(Array)

  ffi_return_type = Fiddle::FFIBackend.to_ffi_type(@return_type)
  ffi_args = @args.map { |t| Fiddle::FFIBackend.to_ffi_type(t) }
  pointer = FFI::Pointer.new(ptr.to_i)
  options = {convention: @abi}
  if ffi_args.last == FFI::Type::Builtin::VARARGS
    @function = FFI::VariadicInvoker.new(
      pointer,
      ffi_args,
      ffi_return_type,
      options
    )
  else
    @function = FFI::Function.new(ffi_return_type, ffi_args, pointer, options)
  end
end

Instance Attribute Details

#abiObject (readonly)

The ABI of the Function.



5
6
7
# File 'lib/fiddle/function.rb', line 5

def abi
  @abi
end

#nameObject (readonly)

The name of this function



11
12
13
# File 'lib/fiddle/function.rb', line 11

def name
  @name
end

#ptrObject (readonly)

The address of this function



8
9
10
# File 'lib/fiddle/function.rb', line 8

def ptr
  @ptr
end

Instance Method Details

#call(argv[], self) ⇒ Object

Calls the constructed Function, with args. Caller must ensure the underlying function is called in a thread-safe manner if running in a multi-threaded process.

Note that it is not thread-safe to use this method to directly or indirectly call many Ruby C-extension APIs unless you don’t pass need_gvl: true to Fiddle::Function#new.

For an example see Fiddle::Function



219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
# File 'function.c', line 219

def call(*args, &block)
  if @function.is_a?(FFI::VariadicInvoker)
    n_fixed_args = @args.size - 1
    n_fixed_args.step(args.size - 1, 2) do |i|
      if args[i] == :const_string || args[i] == Types::CONST_STRING
        args[i + 1] = String.try_convert(args[i + 1]) || args[i + 1]
      end
      args[i] = Fiddle::FFIBackend.to_ffi_type(args[i])
    end
  else
    @args.each_with_index do |arg_type, i|
      next unless arg_type == Types::VOIDP

      src = args[i]
      next if src.nil?
      next if src.is_a?(String)
      next if src.is_a?(FFI::AbstractMemory)
      next if src.is_a?(FFI::Struct)

      args[i] = Pointer[src]
    end
  end
  result = @function.call(*args, &block)
  result = Pointer.new(result) if result.is_a?(FFI::Pointer)
  result
end

#need_gvl?Boolean

Whether GVL is needed to call this function

Returns:

  • (Boolean)


14
15
16
# File 'lib/fiddle/function.rb', line 14

def need_gvl?
  @need_gvl
end

#to_iObject

The integer memory location of this function



19
20
21
# File 'lib/fiddle/function.rb', line 19

def to_i
  ptr.to_i
end

#to_procObject

Turn this function in to a proc



24
25
26
27
# File 'lib/fiddle/function.rb', line 24

def to_proc
  this = self
  lambda { |*args| this.call(*args) }
end