Skip to content

Commit

Permalink
ffi_backend: convert numeric function args to pointers (#162)
Browse files Browse the repository at this point in the history
This allows for passing integers as pointer arguments to functions when
using the FFI backend. This is a workaround until we can get JRuby's FFI
implementation to allow for it directly (see also
jruby/jruby#8423)

---------

Co-authored-by: Benoit Daloze <eregontp@gmail.com>
  • Loading branch information
danini-the-panini and eregon authored Dec 11, 2024
1 parent 77d3dc9 commit e2f0952
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 10 deletions.
21 changes: 12 additions & 9 deletions lib/fiddle/ffi_backend.rb
Original file line number Diff line number Diff line change
Expand Up @@ -159,15 +159,16 @@ def call(*args, &block)
args[i] = Fiddle::FFIBackend.to_ffi_type(args[i])
end
else
args.map! do |arg|
if arg.respond_to?(:to_ptr)
begin
arg = arg.to_ptr
end until arg.is_a?(FFI::Pointer) || !arg.respond_to?(:to_ptr)
arg
else
arg
end
@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)
Expand Down Expand Up @@ -316,6 +317,8 @@ def initialize(addr, size = nil, free = nil)
end
elsif addr.is_a?(IO)
raise NotImplementedError, "IO ptr isn't supported"
else
FFI::Pointer.new(Integer(addr))
end

@size = size ? size : ptr.size
Expand Down
9 changes: 9 additions & 0 deletions test/fiddle/test_function.rb
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,15 @@ def test_call
assert_in_delta 1.0, func.call(90 * Math::PI / 180), 0.0001
end

def test_integer_pointer_conversion
func = Function.new(@libc['memcpy'], [TYPE_VOIDP, TYPE_VOIDP, TYPE_SIZE_T], TYPE_VOIDP)
str = 'hello'
Pointer.malloc(str.bytesize, Fiddle::RUBY_FREE) do |dst|
func.call(dst.to_i, str, dst.size)
assert_equal(str, dst.to_str)
end
end

def test_argument_count
closure_class = Class.new(Closure) do
def call one
Expand Down
8 changes: 7 additions & 1 deletion test/fiddle/test_pointer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -157,11 +157,17 @@ def test_to_ptr_with_ptr
end
end

def test_to_ptr_with_num
def test_to_ptr_with_int
ptr = Pointer.new 0
assert_equal ptr, Pointer[0]
end

MimicInteger = Struct.new(:to_int)
def test_to_ptr_with_to_int
ptr = Pointer.new 0
assert_equal ptr, Pointer[MimicInteger.new(0)]
end

def test_equals
ptr = Pointer.new 0
ptr2 = Pointer.new 0
Expand Down

0 comments on commit e2f0952

Please sign in to comment.