123456789_123456789_123456789_123456789_123456789_

Module: Fiddle

Overview

A libffi wrapper for Ruby.

Description

Fiddle is an extension to translate a foreign function interface (FFI) with ruby.

It wraps / libffi, a popular C library which provides a portable interface that allows code written in one language to call code written in another language.

Example

Here we will use Function to wrap floor(3) from libm

require 'fiddle'

libm = Fiddle.dlopen('/lib/libm.so.6')

floor = Fiddle::Function.new(
  libm['floor'],
  [Fiddle::TYPE_DOUBLE],
  Fiddle::TYPE_DOUBLE
)

puts floor.call(3.14159) #=> 3.0

Constant Summary

Class Attribute Summary

Class Method Summary

  • .dlopen(library) ⇒ Fiddle mod_func

    Creates a new handler that opens library, and returns an instance of Handle.

  • .dlunwrap(addr) mod_func

    Returns the Ruby object stored at the memory address addr

  • .dlwrap(val) mod_func

    Returns the memory address of the Ruby object stored at val

  • .free(addr) mod_func

    Free the memory at address addr

  • .malloc(size) mod_func

    Allocate size bytes of memory and return the integer memory address for the allocated memory.

  • .realloc(addr, size) mod_func

    Change the size of the memory allocated at the memory location addr to size bytes.

Class Attribute Details

.last_error (rw)

Returns the last ::Fiddle::Error of the current executing Thread or nil if none

[ GitHub ]

  
# File 'ext/fiddle/lib/fiddle.rb', line 57

def self.last_error
  if RUBY_ENGINE == 'jruby'
    errno = FFI.errno
    errno == 0 ? nil : errno
  else
    Thread.current[:__FIDDLE_LAST_ERROR__]
  end
end

.last_error=(error) (rw)

Sets the last ::Fiddle::Error of the current executing Thread to error

[ GitHub ]

  
# File 'ext/fiddle/lib/fiddle.rb', line 67

def self.last_error= error
  if RUBY_ENGINE == 'jruby'
    FFI.errno = error || 0
  else
    Thread.current[:__DL2_LAST_ERROR__] = error
    Thread.current[:__FIDDLE_LAST_ERROR__] = error
  end
end

.win32_last_error (rw)

Returns the last win32 ::Fiddle::Error of the current executing Thread or nil if none

[ GitHub ]

  
# File 'ext/fiddle/lib/fiddle.rb', line 16

def self.win32_last_error
  if RUBY_ENGINE == 'jruby'
    errno = FFI.errno
    errno == 0 ? nil : errno
  else
    Thread.current[:__FIDDLE_WIN32_LAST_ERROR__]
  end
end

.win32_last_error=(error) (rw)

Sets the last win32 ::Fiddle::Error of the current executing Thread to error

[ GitHub ]

  
# File 'ext/fiddle/lib/fiddle.rb', line 26

def self.win32_last_error= error
  if RUBY_ENGINE == 'jruby'
    FFI.errno = error || 0
  else
    Thread.current[:__FIDDLE_WIN32_LAST_ERROR__] = error
  end
end

.win32_last_socket_error (rw)

Returns the last win32 socket ::Fiddle::Error of the current executing Thread or nil if none

[ GitHub ]

  
# File 'ext/fiddle/lib/fiddle.rb', line 36

def self.win32_last_socket_error
  if RUBY_ENGINE == 'jruby'
    errno = FFI.errno
    errno == 0 ? nil : errno
  else
    Thread.current[:__FIDDLE_WIN32_LAST_SOCKET_ERROR__]
  end
end

.win32_last_socket_error=(error) (rw)

Sets the last win32 socket ::Fiddle::Error of the current executing Thread to error

[ GitHub ]

  
# File 'ext/fiddle/lib/fiddle.rb', line 47

def self.win32_last_socket_error= error
  if RUBY_ENGINE == 'jruby'
    FFI.errno = error || 0
  else
    Thread.current[:__FIDDLE_WIN32_LAST_SOCKET_ERROR__] = error
  end
end

Class Method Details

.dlopen(library) ⇒ Fiddle (mod_func)

Creates a new handler that opens library, and returns an instance of ::Fiddle::Handle.

If nil is given for the library, Handle::DEFAULT is used, which is the equivalent to RTLD_DEFAULT. See man 3 dlopen for more.

lib = Fiddle.dlopen(nil)

The default is dependent on OS, and provide a handle for all libraries already loaded. For example, in most cases you can use this to access libc functions, or ruby functions like rb_str_new.

See Handle.new for more.

[ GitHub ]

  
# File 'ext/fiddle/lib/fiddle.rb', line 91

def dlopen library
  begin
    Fiddle::Handle.new(library)
  rescue DLError => error
    case RUBY_PLATFORM
    when /linux/
      case error.message
      when /\A(\/.+?): (?:invalid ELF header|file too short)/
        # This may be a linker script:
        # https://sourceware.org/binutils/docs/ld.html#Scripts
        path = $1
      else
        raise
      end
    else
      raise
    end

    File.open(path) do |input|
      input.each_line do |line|
        case line
        when /\A\s*(?:INPUT|GROUP)\s*\(\s*([^\s,\)]+)/
          # TODO: Should we support multiple files?
          return dlopen($1)
        end
      end
    end

    # Not found
    raise
  end
end

.dlunwrap(addr) (mod_func)

Returns the Ruby object stored at the memory address addr

Example:

x = Object.new
# => #<Object:0x0000000107c7d870>
Fiddle.dlwrap(x)
# => 4425504880
Fiddle.dlunwrap(_)
# => #<Object:0x0000000107c7d870>
[ GitHub ]

  
# File 'ext/fiddle/fiddle.c', line 74

VALUE
rb_fiddle_ptr2value(VALUE self, VALUE addr)
{
    return (VALUE)NUM2PTR(addr);
}

.dlwrap(val) (mod_func)

Returns the memory address of the Ruby object stored at val

Example:

x = Object.new
# => #<Object:0x0000000107c7d870>
Fiddle.dlwrap(x)
# => 4425504880

In the case val is not a heap allocated object, this method will return the tagged pointer value.

Example:

Fiddle.dlwrap(123)
# => 247
[ GitHub ]

  
# File 'ext/fiddle/fiddle.c', line 100

static VALUE
rb_fiddle_value2ptr(VALUE self, VALUE val)
{
    return PTR2NUM((void*)val);
}

.free(addr) (mod_func)

Free the memory at address addr

[ GitHub ]

  
# File 'ext/fiddle/fiddle.c', line 51

VALUE
rb_fiddle_free(VALUE self, VALUE addr)
{
    void *ptr = NUM2PTR(addr);

    ruby_xfree(ptr);
    return Qnil;
}

.malloc(size) (mod_func)

Allocate size bytes of memory and return the integer memory address for the allocated memory.

[ GitHub ]

  
# File 'ext/fiddle/fiddle.c', line 22

static VALUE
rb_fiddle_malloc(VALUE self, VALUE size)
{
    void *ptr;
    ptr = (void*)ruby_xcalloc(1, NUM2SIZET(size));
    return PTR2NUM(ptr);
}

.realloc(addr, size) (mod_func)

Change the size of the memory allocated at the memory location addr to size bytes. Returns the memory address of the reallocated memory, which may be different than the address passed in.

[ GitHub ]

  
# File 'ext/fiddle/fiddle.c', line 37

static VALUE
rb_fiddle_realloc(VALUE self, VALUE addr, VALUE size)
{
    void *ptr = NUM2PTR(addr);

    ptr = (void*)ruby_xrealloc(ptr, NUM2SIZET(size));
    return PTR2NUM(ptr);
}