diff --git a/lib/fiddle/ffi_backend.rb b/lib/fiddle/ffi_backend.rb index fc1746fd..275d090c 100644 --- a/lib/fiddle/ffi_backend.rb +++ b/lib/fiddle/ffi_backend.rb @@ -218,8 +218,8 @@ class Error < StandardError; end class DLError < Error; end class ClearedReferenceError < Error; end + # Pointer isn't thread safe for now class Pointer - attr_reader :ffi_ptr extend FFI::DataConverter native_type FFI::Type::Builtin::POINTER @@ -285,7 +285,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 +293,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 +332,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 +368,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 +391,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 +497,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")