From 7c260bd424c25755554885fb1bc25492e5df598f Mon Sep 17 00:00:00 2001 From: Dani Smith Date: Thu, 12 Dec 2024 01:43:51 +0200 Subject: [PATCH] [ruby/fiddle] ffi_backend: convert numeric function args to pointers (https://github.com/ruby/fiddle/pull/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 https://github.com/jruby/jruby/pull/8423) --------- https://github.com/ruby/fiddle/commit/e2f0952e9b Co-authored-by: Benoit Daloze --- ext/fiddle/lib/fiddle/ffi_backend.rb | 21 ++++++++++++--------- test/fiddle/test_function.rb | 9 +++++++++ test/fiddle/test_pointer.rb | 8 +++++++- 3 files changed, 28 insertions(+), 10 deletions(-) diff --git a/ext/fiddle/lib/fiddle/ffi_backend.rb b/ext/fiddle/lib/fiddle/ffi_backend.rb index 0f068a75e0..5cfceb19a8 100644 --- a/ext/fiddle/lib/fiddle/ffi_backend.rb +++ b/ext/fiddle/lib/fiddle/ffi_backend.rb @@ -159,15 +159,16 @@ module Fiddle 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) @@ -316,6 +317,8 @@ module Fiddle 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 diff --git a/test/fiddle/test_function.rb b/test/fiddle/test_function.rb index 146dcc7205..b408a14ccd 100644 --- a/test/fiddle/test_function.rb +++ b/test/fiddle/test_function.rb @@ -98,6 +98,15 @@ module Fiddle 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 diff --git a/test/fiddle/test_pointer.rb b/test/fiddle/test_pointer.rb index 673e7ca445..9d490f9f26 100644 --- a/test/fiddle/test_pointer.rb +++ b/test/fiddle/test_pointer.rb @@ -157,11 +157,17 @@ module Fiddle 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