Cで書かれたRuby gemをFFIでRubyに移植しています。
MRI Ruby を使用してテストを実行すると、セグ フォールトはありません。jRuby で実行すると、seg-fault が発生します。
これは、責任があると思われるテストのコードです。
if type == Date or type == DateTime then
assert_nil param.set_value(value.strftime("%F %T"));
else
assert_nil param.set_value(value);
end
@api.sqlany_bind_param(stmt, 0, param)
puts "\n#{param.inspect}"
#return if String === value or Date === value or DateTime === value
assert_succeeded @api.sqlany_execute(stmt)
セグメンテーション違反は、sqlany_execute の実行時に発生しますが、set_value に渡されたオブジェクトがクラス String である場合にのみ発生します。
sqlany_execute は、FFI の attach_function メソッドを使用するだけです。
param.set_value はより複雑です。String 固有の部分だけに焦点を当てます。これが元のCコードです
case T_STRING:
s_bind->value.length = malloc(sizeof(size_t));
length = RSTRING_LEN(val);
*s_bind->value.length = length;
s_bind->value.buffer = malloc(length);
memcpy(s_bind->value.buffer, RSTRING_PTR(val), length);
s_bind->value.type = A_STRING;
break;
私のポートでは、これは次のようになりました。
when String
self[:value][:length] = SQLAnywhere::LibC.malloc(FFI::Type::ULONG.size)
length = value.bytesize
self[:value][:length].write_int(length)
self[:value][:buffer] = SQLAnywhere::LibC.malloc(length + 1)
self[:value][:buffer_size] = length + 1
## Don't use put_string as that includes the terminating null
# value.each_byte.each_with_index do |byte, index|
# self[:value][:buffer].put_uchar(index, byte)
# end
self[:value][:buffer].put_string(0, value)
self[:value][:type] = :string
私の質問は、jRuby がセグメンテーション フォールトを引き起こしている原因と、それに対して何ができるかということです。