Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: jruby/jruby
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: af0556bb4f7d
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 70a471e11fbc
Choose a head ref
  • 20 commits
  • 3 files changed
  • 2 contributors

Commits on Feb 25, 2017

  1. fix: test fiddle helper not detecting platform properly

    Daniel Smith committed Feb 25, 2017
    Copy the full SHA
    6d129b7 View commit details
  2. fix: incorrect invokation of __ffi_type__

    Daniel Smith committed Feb 25, 2017
    Copy the full SHA
    8f5b4c6 View commit details
  3. fix: add TYPE_PTRDIFF_T and friends

    Daniel Smith committed Feb 25, 2017
    Copy the full SHA
    a71de6b View commit details
  4. fix: make Fiddle::Pointer [] and []= act like MRI

    Daniel Smith committed Feb 25, 2017
    Copy the full SHA
    439fdf2 View commit details
  5. Copy the full SHA
    6d0fddc View commit details
  6. fix: Fiddle.malloc and Fiddle::Pointer.malloc

    Daniel Smith committed Feb 25, 2017
    Copy the full SHA
    df4576c View commit details
  7. feat: add Fiddle::NULL

    Daniel Smith committed Feb 25, 2017
    Copy the full SHA
    a326b22 View commit details

Commits on Feb 26, 2017

  1. Copy the full SHA
    cf888ad View commit details
  2. feat: add Fiddle.free and Fiddle::RUBY_FREE

    Daniel Smith committed Feb 26, 2017
    Copy the full SHA
    a69a01d View commit details
  3. feat: add missing RUBY_BUILD_PLATFORM

    I just made it equal to RUBY_PLATFORM, which will always be Java
    Daniel Smith committed Feb 26, 2017
    Copy the full SHA
    f3accf8 View commit details
  4. Throw DLError when to_ptr does not return a Pointer

    Behaves more like MRI
    Daniel Smith committed Feb 26, 2017
    Copy the full SHA
    ecee875 View commit details
  5. Make Pointer#free and act more like MRI

    Pointer#free= should accept an Integer or Pointer
    Pointer#free should return a new instance of Fiddle::Function
    Pointer#free should return nil if free is zero
    Daniel Smith committed Feb 26, 2017
    Copy the full SHA
    9dd4aa0 View commit details
  6. Add comparison operators to Fiddle::Pointer

    Daniel Smith committed Feb 26, 2017
    Copy the full SHA
    9739631 View commit details
  7. Fix Fiddle::Pointer arithmetic not working

    Daniel Smith committed Feb 26, 2017
    Copy the full SHA
    1be0429 View commit details
  8. Fiddle::Pointer.new should accept anything Integer-like as an address

    Behaves more like MRI. Previously passing something in that was neither an FFI::Pointer nor an Integer would cause undesirable results.
    Daniel Smith committed Feb 26, 2017
    Copy the full SHA
    4b41af5 View commit details
  9. Make Pointer#to_s and Pointer#to_str behave like MRI

    The difference is, without passing `len` in to the function:
    1. to_s returns a null-terminated string
    2. to_str returns a string of as many bytes a the pointer's size
    Daniel Smith committed Feb 26, 2017
    Copy the full SHA
    771d488 View commit details
  10. Throw DLError instead of FFI:: NullPointerError

    Daniel Smith committed Feb 26, 2017
    Copy the full SHA
    65ee829 View commit details
  11. Make Pointer#[]= act even more like MRI

    Some hidden, undocumented "features" of Pointer#[]= include:
    1. Passing a Pointer instead of a String, whereby data is copied from the passed-in pointer
    2. Passing an Integer instead of a string, using the integer as a memory address to copy from
    Daniel Smith committed Feb 26, 2017
    Copy the full SHA
    0da8739 View commit details
  12. Credit original author of ffi-libc

    Daniel Smith committed Feb 26, 2017
    Copy the full SHA
    3e883a5 View commit details

Commits on Mar 1, 2017

  1. Merge pull request #4511 from jellymann/ds-fix-fiddle

    Fix some issues with Fiddle
    headius authored Mar 1, 2017
    Copy the full SHA
    70a471e View commit details
Showing with 326 additions and 21 deletions.
  1. +218 −0 lib/ruby/stdlib/ffi/libc.rb
  2. +103 −20 lib/ruby/stdlib/fiddle/jruby.rb
  3. +5 −1 test/mri/fiddle/helper.rb
218 changes: 218 additions & 0 deletions lib/ruby/stdlib/ffi/libc.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
# Originally from https://github.com/postmodern/ffi-libc

module FFI
module LibC
extend FFI::Library

typedef :pointer, :FILE
typedef :uint32, :in_addr_t
typedef :uint16, :in_port_t

# time.h
typedef :long, :clock_t

ffi_lib [FFI::CURRENT_PROCESS, 'c']

# The NULL constant
NULL = nil

# errno.h
attach_variable :sys_errlist, :pointer
attach_variable :sys_nerr, :int
attach_variable :errno, :int

def self.raise_error(error=self.errno)
raise(strerror(error))
end

# unistd.h
attach_function :brk, [:pointer], :int
attach_function :sbrk, [:pointer], :pointer
attach_function :getpid, [], :pid_t
attach_function :getppid, [], :pid_t
attach_function :getuid, [], :uid_t
attach_function :geteuid, [], :uid_t
attach_function :getgid, [], :gid_t
attach_function :getegid, [], :gid_t
attach_function :alarm, [:uint], :uint

# stdlib.h
attach_function :calloc, [:size_t, :size_t], :pointer
attach_function :malloc, [:size_t], :pointer
FREE = attach_function :free, [:pointer], :void
attach_function :realloc, [:pointer, :size_t], :pointer
attach_function :getenv, [:string], :string
attach_function :putenv, [:string], :int
attach_function :unsetenv, [:string], :int

begin
attach_function :clearenv, [], :int
rescue FFI::NotFoundError
# clearenv is not available on OSX
end

# time.h
attach_function :clock, [], :clock_t
attach_function :time, [:pointer], :time_t

# sys/time.h
attach_function :gettimeofday, [:pointer, :pointer], :int
attach_function :settimeofday, [:pointer, :pointer], :int

# sys/mman.h
attach_function :mmap, [:pointer, :size_t, :int, :int, :int, :off_t], :pointer
attach_function :munmap, [:pointer, :size_t], :int

# string.h
attach_function :bzero, [:pointer, :size_t], :void
attach_function :memset, [:pointer, :int, :size_t], :pointer
attach_function :memcpy, [:buffer_out, :buffer_in, :size_t], :pointer
attach_function :memcmp, [:buffer_in, :buffer_in, :size_t], :int
attach_function :memchr, [:buffer_in, :int, :size_t], :pointer

begin
attach_function :memrchr, [:buffer_in, :int, :size_t], :pointer
rescue FFI::NotFoundError
# memrchr is not available on OSX
end

attach_function :strcpy, [:buffer_out, :string], :pointer
attach_function :strncpy, [:buffer_out, :string, :size_t], :pointer
attach_function :strcmp, [:buffer_in, :buffer_in], :int
attach_function :strncmp, [:buffer_in, :buffer_in, :size_t], :int
attach_function :strlen, [:buffer_in], :size_t
attach_function :index, [:buffer_in, :int], :pointer
attach_function :rindex, [:buffer_in, :int], :pointer
attach_function :strchr, [:buffer_in, :int], :pointer
attach_function :strrchr, [:buffer_in, :int], :pointer
attach_function :strstr, [:buffer_in, :string], :pointer
attach_function :strerror, [:int], :string

begin
attach_variable :stdin, :pointer
attach_variable :stdout, :pointer
attach_variable :stderr, :pointer
rescue FFI::NotFoundError
# stdin, stdout, stderr are not available on OSX
end

attach_function :fopen, [:string, :string], :FILE
attach_function :fdopen, [:int, :string], :FILE
attach_function :freopen, [:string, :string, :FILE], :FILE
attach_function :fseek, [:FILE, :long, :int], :int
attach_function :ftell, [:FILE], :long
attach_function :rewind, [:FILE], :void
attach_function :fread, [:buffer_out, :size_t, :size_t, :FILE], :size_t
attach_function :fwrite, [:buffer_in, :size_t, :size_t, :FILE], :size_t
attach_function :fgetc, [:FILE], :int
attach_function :fgets, [:buffer_out, :int, :FILE], :pointer
attach_function :fputc, [:int, :FILE], :int
attach_function :fputs, [:buffer_in, :FILE], :int
attach_function :fflush, [:FILE], :int
attach_function :fclose, [:FILE], :int
attach_function :clearerr, [:FILE], :void
attach_function :feof, [:FILE], :int
attach_function :ferror, [:FILE], :int
attach_function :fileno, [:FILE], :int
attach_function :perror, [:string], :void

attach_function :getc, [:FILE], :int
attach_function :getchar, [], :int
attach_function :gets, [:buffer_out], :int
attach_function :ungetc, [:int, :pointer], :int

attach_function :putc, [:int, :FILE], :int
attach_function :putchar, [:int], :int
attach_function :puts, [:string], :int

# netdb.h
attach_function :getnameinfo, [
:pointer,
:socklen_t, :pointer,
:socklen_t, :pointer,
:socklen_t, :int
], :int

NI_MAXHOST = 1024
NI_MAXSERV = 32

NI_NUMERICHOST = 1 # Don't try to look up hostname.
NI_NUMERICSERV = 2 # Don't convert port number to name.
NI_NOFQDN = 4 # Only return nodename portion.
NI_NAMEREQD = 8 # Don't return numeric addresses.
NI_DGRAM = 16 # Look up UDP service rather than TCP.

# ifaddrs.h
attach_function :getifaddrs, [:pointer], :int
attach_function :freeifaddrs, [:pointer], :void

#
# Enumerates over the Interface Addresses.
#
# @yield [ifaddr]
# The given block will be passed each Interface Address.
#
# @yieldparam [Ifaddrs] ifaddr
# An Interface Address.
#
# @return [Enumerator]
# If no block is given, an enumerator will be returned.
#
# @since 0.1.0
#
def self.each_ifaddr
return enum_for(__method__) unless block_given?

ptr = MemoryPointer.new(:pointer)

if getifaddrs(ptr) == -1
raise_error
end

if (ifaddrs = ptr.get_pointer(0)).null?
return
end

ifaddr = Ifaddrs.new(ifaddrs)

while ifaddr
yield ifaddr

ifaddr = ifaddr.next
end

freeifaddrs(ifaddrs)
end

# bits/resource.h (Linux) / sys/resource.h (Darwin)
RUSAGE_SELF = 0
RUSAGE_CHILDREN = -1
RUSAGE_THREAD = 1 # Linux/glibc only

attach_function :getrusage, [:int, :pointer], :int

#
# Gets the RUsage for the user.
#
# @param [RUSAGE_SELF, RUSAGE_CHILDREN, RUSAGE_THREAD] who
# Whome to get RUsage statistics for.
#
# @return [RUsage]
# The RUsage statistics.
#
# @raise [RuntimeError]
# An error has occurred.
#
# @since 0.1.0
#
def self.rusage(who=RUSAGE_SELF)
rusage = RUsage.new

unless (ret = getrusage(who,rusage)) == 0
raise_error(ret)
end

return rusage
end
end
end
123 changes: 103 additions & 20 deletions lib/ruby/stdlib/fiddle/jruby.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
require 'ffi'
require 'ffi/libc'

module Fiddle
TYPE_VOID = 0
@@ -11,8 +12,27 @@ module Fiddle
TYPE_FLOAT = 7
TYPE_DOUBLE = 8

TYPE_SIZE_T = -5
TYPE_SSIZE_T = 5
TYPE_PTRDIFF_T = 5
TYPE_INTPTR_T = 5
TYPE_UINTPTR_T = -5

WINDOWS = FFI::Platform.windows?

LibC = FFI::LibC
RUBY_FREE = LibC::FREE.address

BUILD_RUBY_PLATFORM = RUBY_PLATFORM

def self.malloc(size)
LibC.malloc(size)
end

def self.free(ptr)
LibC.free(Pointer.to_native(ptr, nil))
end

module JRuby
FFITypes = {
'c' => FFI::Type::INT8,
@@ -57,7 +77,7 @@ def initialize(ptr, args, return_type, abi = DEFAULT, kwargs = nil)
@ptr, @args, @return_type, @abi = ptr, args, return_type, abi
raise TypeError.new "invalid return type" unless return_type.is_a?(Integer)
raise TypeError.new "invalid return type" unless args.is_a?(Array)

@function = FFI::Function.new(
Fiddle::JRuby::__ffi_type__(@return_type),
@args.map { |t| Fiddle::JRuby.__ffi_type__(t) },
@@ -78,7 +98,7 @@ def initialize(ret, args, abi = Function::DEFAULT)
raise TypeError.new "invalid return type" unless args.is_a?(Array)

@function = FFI::Function.new(
__ffi_type__(@ctype),
Fiddle::JRuby::__ffi_type__(@ctype),
@args.map { |t| Fiddle::JRuby.__ffi_type__(t) },
self,
:convention => abi
@@ -122,7 +142,11 @@ def self.to_ptr(value)

elsif value.respond_to?(:to_ptr)
ptr = value.to_ptr
ptr.is_a?(Pointer) ? ptr : Pointer.new(ptr)
if ptr.is_a?(Pointer)
ptr
else
raise DLError.new('to_ptr should return a Fiddle::Pointer object')
end

else
Pointer.new(value)
@@ -133,17 +157,16 @@ class << self
alias [] to_ptr
end

def initialize(addr, size = nil, free = nil)
def initialize(addr, size = 0, freefunc = nil)
ptr = if addr.is_a?(FFI::Pointer)
addr

elsif addr.is_a?(Integer)
FFI::Pointer.new(addr)
else
FFI::Pointer.new(Integer(addr))
end

@size = size ? size : ptr.size
@free = free
@ffi_ptr = free.nil? ? ptr : FFI::AutoPointer.new(ptr, self.class.__freefunc__(free))
@size = size
self.free = freefunc
@ffi_ptr = freefunc.nil? ? ptr : FFI::AutoPointer.new(ptr, ->(x){@__freefunc__.call(x)})
end

def self.__freefunc__(free)
@@ -165,7 +188,7 @@ def self.__freefunc__(free)
end

def self.malloc(size, free = nil)
self.new(LibC.malloc(size), size, free ? free : LibC::FREE)
self.new(Fiddle.malloc(size), size, free)
end

def null?
@@ -184,38 +207,84 @@ def size=(size)
@size = size
end

def free
return nil if @free.zero?
Function.new(@free, [TYPE_VOIDP], TYPE_VOID)
end

def free=(freefunc)
if freefunc.nil?
@free = 0
@__freefunc__ = Proc.new { |ptr| }
else
@free = Integer(freefunc)
@__freefunc__ = self.class.__freefunc__(freefunc)
end
end

def [](index, length = nil)
if length
ffi_ptr.get_string(index, length)
ffi_ptr.get_bytes(index, length)
else
ffi_ptr.get_int8(index)
end
rescue FFI::NullPointerError
raise DLError.new('NULL pointer dereference')
end

def []=(index, length = nil, value)
if length
if value.is_a?(Integer)
value_str = Pointer.new(value).to_s
else
value_str = value.to_str
end
ffi_ptr.put_bytes(index, value_str, 0, [length, value_str.bytesize].min)
else
ffi_ptr.get_int(index)
ffi_ptr.put_int8(index, value)
end
rescue FFI::NullPointerError
raise DLError.new('NULL pointer dereference')
end

def to_i
ffi_ptr.to_i
end
alias to_int to_i

def to_str(len = nil)
def to_s(len = nil)
if len
ffi_ptr.get_string(0, len)
ffi_ptr.get_bytes(0, len)
else
ffi_ptr.get_string(0)
end
end
alias to_s to_str

def to_str(len = size)
ffi_ptr.get_bytes(0, len)
end

def inspect
"#<#{self.class.name} ptr=#{ffi_ptr.address.to_s(16)} size=#{@size} free=#{@free.inspect}>"
"#<#{self.class.name} ptr=#{ffi_ptr.address.to_s(16)} size=#{@size} free=#{@free.to_s(16)}>"
end

def +(delta)
self.class.new(ffi_ptr + delta, @size - delta)
self.class.new(ffi_ptr.address + delta, @size - delta)
end

def -(delta)
self.class.new(ffi_ptr - delta, @size + delta)
self.class.new(ffi_ptr.address - delta, @size + delta)
end

def ==(value)
return false unless value.is_a?(Pointer)
self.ffi_ptr.address == value.ffi_ptr.address
end
alias eql? ==

def <=>(value)
return nil unless value.is_a?(Pointer)
self.ffi_ptr.address <=> value.ffi_ptr.address
end

def ptr
@@ -229,6 +298,8 @@ def ref
end
end

NULL = Pointer.new(0, 0, 0)

class Handle
RTLD_GLOBAL = FFI::DynamicLibrary::RTLD_GLOBAL
RTLD_LAZY = FFI::DynamicLibrary::RTLD_LAZY
@@ -303,4 +374,16 @@ def disable_close
SIZEOF_LONG_LONG = Fiddle::JRuby::FFITypes[TYPE_LONG_LONG].size
SIZEOF_FLOAT = Fiddle::JRuby::FFITypes[TYPE_FLOAT].size
SIZEOF_DOUBLE = Fiddle::JRuby::FFITypes[TYPE_DOUBLE].size
end

ALIGN_SIZE_T = ALIGN_VOIDP
ALIGN_SSIZE_T = ALIGN_VOIDP
ALIGN_PTRDIFF_T = ALIGN_VOIDP
ALIGN_INTPTR_T = ALIGN_VOIDP
ALIGN_UINTPTR_T = ALIGN_VOIDP

SIZEOF_SIZE_T = SIZEOF_VOIDP
SIZEOF_SSIZE_T = SIZEOF_VOIDP
SIZEOF_PTRDIFF_T = SIZEOF_VOIDP
SIZEOF_INTPTR_T = SIZEOF_VOIDP
SIZEOF_UINTPTR_T = SIZEOF_VOIDP
end
6 changes: 5 additions & 1 deletion test/mri/fiddle/helper.rb
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
# frozen_string_literal: false
require 'minitest/autorun'
require 'fiddle'
require 'rbconfig'

# FIXME: this is stolen from DL and needs to be refactored.

libc_so = libm_so = nil

case RUBY_PLATFORM
platform = RUBY_PLATFORM
platform = RbConfig::CONFIG['target_os'] if platform == 'java'

case platform
when /cygwin/
libc_so = "cygwin1.dll"
libm_so = "cygwin1.dll"