From 5ef1e527a1d807d3023f0ac989b415fe6175af8b Mon Sep 17 00:00:00 2001 From: Andrew Kane Date: Tue, 22 Apr 2025 20:16:16 -0700 Subject: [PATCH 1/2] Fix Fiddle::Pointer#ref behavior for FFI backend --- lib/fiddle/ffi_backend.rb | 24 +++++++++++++----------- test/fiddle/test_pointer.rb | 13 +++++++++++++ 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/lib/fiddle/ffi_backend.rb b/lib/fiddle/ffi_backend.rb index fc1746fd..37f8b936 100644 --- a/lib/fiddle/ffi_backend.rb +++ b/lib/fiddle/ffi_backend.rb @@ -219,7 +219,6 @@ class DLError < Error; end class ClearedReferenceError < Error; end class Pointer - attr_reader :ffi_ptr extend FFI::DataConverter native_type FFI::Type::Builtin::POINTER @@ -285,7 +284,7 @@ def []=(*args, value) value = value.to_str(args[1]) end - @ffi_ptr.put_bytes(args[0], value, 0, args[1]) + ffi_ptr.put_bytes(args[0], value, 0, args[1]) elsif args.size == 1 if value.is_a?(Fiddle::Pointer) value = value.to_str(args[0] + 1) @@ -293,7 +292,7 @@ def []=(*args, value) value = value.chr end - @ffi_ptr.put_bytes(args[0], value, 0, 1) + ffi_ptr.put_bytes(args[0], value, 0, 1) end rescue FFI::NullPointerError raise DLError.new("NULL pointer access") @@ -332,9 +331,14 @@ def initialize(addr, size = nil, free = nil) end @free = free @ffi_ptr = ptr + @addr_ptr = nil @freed = false end + def ffi_ptr + @addr_ptr ? @addr_ptr.get_pointer(0) : @ffi_ptr + end + module LibC extend FFI::Library ffi_lib FFI::Library::LIBC @@ -363,11 +367,11 @@ def self.malloc(size, free = nil) end def null? - @ffi_ptr.null? + ffi_ptr.null? end def to_ptr - @ffi_ptr + ffi_ptr end def size @@ -386,9 +390,9 @@ def call_free return if @free.nil? return if @freed if @free == RUBY_FREE - LibC::FREE.call(@ffi_ptr) + LibC::FREE.call(ffi_ptr) else - @free.call(@ffi_ptr) + @free.call(ffi_ptr) end @freed = true end @@ -492,10 +496,8 @@ def -@ end def ref - cptr = Pointer.malloc(FFI::Type::POINTER.size, RUBY_FREE) - cptr.ffi_ptr.put_pointer(0, ffi_ptr) - cptr.size = 0 - cptr + @addr_ptr ||= FFI::MemoryPointer.new(:pointer).put_pointer(0, @ffi_ptr) + Pointer.new(@addr_ptr, 0) end end diff --git a/test/fiddle/test_pointer.rb b/test/fiddle/test_pointer.rb index 6f086f00..da2cc20c 100644 --- a/test/fiddle/test_pointer.rb +++ b/test/fiddle/test_pointer.rb @@ -187,6 +187,19 @@ def test_cmp assert_nil(ptr <=> 10, '10 should not be comparable') end + def test_ref + ptr = Fiddle::Pointer["hello"] + ref = ptr.ref + assert_equal(0, ref.size) + assert_nil(ref.free) + assert_equal(ptr, ref.ptr) + + ptr2 = Fiddle::Pointer["world"] + ptr.ref[0, Fiddle::SIZEOF_VOIDP] = ptr2.ref + assert_equal("world", ptr.to_s) + assert_equal(ptr.to_i, ptr2.to_i) + end + def test_ref_ptr if ffi_backend? omit("Fiddle.dlwrap([]) isn't supported with FFI backend") From 746747071b6154813518822c3106bf1ad43df8a7 Mon Sep 17 00:00:00 2001 From: Andrew Kane Date: Tue, 22 Apr 2025 22:09:54 -0700 Subject: [PATCH 2/2] Add note about pointer thread safety for FFI backend [skip ci] --- lib/fiddle/ffi_backend.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/fiddle/ffi_backend.rb b/lib/fiddle/ffi_backend.rb index 37f8b936..275d090c 100644 --- a/lib/fiddle/ffi_backend.rb +++ b/lib/fiddle/ffi_backend.rb @@ -218,6 +218,7 @@ class Error < StandardError; end class DLError < Error; end class ClearedReferenceError < Error; end + # Pointer isn't thread safe for now class Pointer extend FFI::DataConverter native_type FFI::Type::Builtin::POINTER