Skip to content

Commit e2f0952

Browse files
ffi_backend: convert numeric function args to pointers (#162)
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>
1 parent 77d3dc9 commit e2f0952

File tree

3 files changed

+28
-10
lines changed

3 files changed

+28
-10
lines changed

lib/fiddle/ffi_backend.rb

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -159,15 +159,16 @@ def call(*args, &block)
159159
args[i] = Fiddle::FFIBackend.to_ffi_type(args[i])
160160
end
161161
else
162-
args.map! do |arg|
163-
if arg.respond_to?(:to_ptr)
164-
begin
165-
arg = arg.to_ptr
166-
end until arg.is_a?(FFI::Pointer) || !arg.respond_to?(:to_ptr)
167-
arg
168-
else
169-
arg
170-
end
162+
@args.each_with_index do |arg_type, i|
163+
next unless arg_type == Types::VOIDP
164+
165+
src = args[i]
166+
next if src.nil?
167+
next if src.is_a?(String)
168+
next if src.is_a?(FFI::AbstractMemory)
169+
next if src.is_a?(FFI::Struct)
170+
171+
args[i] = Pointer[src]
171172
end
172173
end
173174
result = @function.call(*args, &block)
@@ -316,6 +317,8 @@ def initialize(addr, size = nil, free = nil)
316317
end
317318
elsif addr.is_a?(IO)
318319
raise NotImplementedError, "IO ptr isn't supported"
320+
else
321+
FFI::Pointer.new(Integer(addr))
319322
end
320323

321324
@size = size ? size : ptr.size

test/fiddle/test_function.rb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,15 @@ def test_call
9898
assert_in_delta 1.0, func.call(90 * Math::PI / 180), 0.0001
9999
end
100100

101+
def test_integer_pointer_conversion
102+
func = Function.new(@libc['memcpy'], [TYPE_VOIDP, TYPE_VOIDP, TYPE_SIZE_T], TYPE_VOIDP)
103+
str = 'hello'
104+
Pointer.malloc(str.bytesize, Fiddle::RUBY_FREE) do |dst|
105+
func.call(dst.to_i, str, dst.size)
106+
assert_equal(str, dst.to_str)
107+
end
108+
end
109+
101110
def test_argument_count
102111
closure_class = Class.new(Closure) do
103112
def call one

test/fiddle/test_pointer.rb

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,11 +157,17 @@ def test_to_ptr_with_ptr
157157
end
158158
end
159159

160-
def test_to_ptr_with_num
160+
def test_to_ptr_with_int
161161
ptr = Pointer.new 0
162162
assert_equal ptr, Pointer[0]
163163
end
164164

165+
MimicInteger = Struct.new(:to_int)
166+
def test_to_ptr_with_to_int
167+
ptr = Pointer.new 0
168+
assert_equal ptr, Pointer[MimicInteger.new(0)]
169+
end
170+
165171
def test_equals
166172
ptr = Pointer.new 0
167173
ptr2 = Pointer.new 0

0 commit comments

Comments
 (0)