Subject:
[ruby-ffi] using :buffer_out with strings in ruby vs jruby
From:
Aman Gupta
Date:
9/14/09 4:07 AM
To:
ruby-ffi


I'm seeing different behavior on ruby vs jruby when passing in a
string as a :buffer_out argument:

require 'rubygems'
require 'ffi'

module GLib
  extend FFI::Library
  ffi_lib 'libglib-2.0'
  attach_function :g_memdup_buf, :g_memdup,
[ :buffer_out, :uint ], :pointer
  attach_function :g_memdup_ptr, :g_memdup,
[ :pointer, :uint ], :pointer

  def self.test_memdup(arg_type, func_type)
    ostr = "a\0b\0c"

    if arg_type == :string
      arg = ostr.dup
    elsif arg_type == :buffer
      arg = FFI::Buffer.new(ostr.size)
      arg.put_bytes(0, ostr)
    end

    if func_type == :buffer_out
      ret = GLib.g_memdup_buf(arg, arg.size)
    elsif func_type == :pointer
      ret = GLib.g_memdup_ptr(arg, arg.size)
    end

    rstr = ret.get_bytes(0, ostr.size)

    p [arg_type, func_type, ostr, rstr, ostr == rstr]
  end
end

GLib.test_memdup(:buffer, :buffer_out)
GLib.test_memdup(:buffer, :pointer)
GLib.test_memdup(:string, :buffer_out)
GLib.test_memdup(:string, :pointer)

$ ruby glib_memduptest.rb
[:buffer, :buffer_out, "a\000b\000c", "a\000b\000c", true]
[:buffer, :pointer, "a\000b\000c", "a\000b\000c", true]
[:string, :buffer_out, "a\000b\000c", "a\000b\000c", true]
[:string, :pointer, "a\000b\000c", "a\000b\000c", true]

$ jruby glib_memduptest.rb
[:buffer, :buffer_out, "a\000b\000c", "\300\370\177\260A", false]
[:buffer, :pointer, "a\000b\000c", "a\000b\000c", true]
[:string, :buffer_out, "\001\000\000\000\270", "\001\000\000\000\270",
true]
[:string, :pointer, "\001\000\000\000\270", "\001\000\000\000\270",
true]

I'm not really sure what's happening in the jruby case. If I use an
explicit FFI::Buffer with :pointer, it seems to work.

What's really strange though, is that if you reverse the order in
which the tests happen (so the string versions execute first), they
all fail:

GLib.test_memdup(:string, :buffer_out)
GLib.test_memdup(:string, :pointer)
GLib.test_memdup(:buffer, :buffer_out)
GLib.test_memdup(:buffer, :pointer)

$ jruby glib_memduptest.rb
[:string, :buffer_out, "\300\370\177\260A", "\300\370\177\260A", true]
[:string, :pointer, "\300\370\177\260A", "\300\370\177\260A", true]
[:buffer, :buffer_out, "\300\370\177\260A", "0\f\200\001@", false]
[:buffer, :pointer, "\300\370\177\260A", "\300\370\177\260A", true]