Fiddleの構造体のメンバーを何回も呼び出すと値が変わってしまうことがあります。
意気揚々としてisssue報告をしたのでしたが…
下、1000回呼び出すとだいたい値が変化する…
require 'fiddle/import'
module A
extend Fiddle::Importer
S = struct [
'int8_t* hoge',
'int8_t* fuga']
end
s = A::S.malloc
s.hoge = [*1..10].pack('c*')
s.fuga = [*1..10].reverse.pack('c*')
a1 = s.fuga[0,10].unpack('c*')
1000.times do
s.fuga[0,10].unpack('c*')
end
b1 = s.fuga[0,10].unpack('c*')
if a1 == b1
puts "OK"
else
p a1, b1
end
ところが、これはバグではなく、文字列がGCによって回収されてしまうのだそうです。
以前にもFiddle::Closure::BlockCallerがGC回収されてしまう記事を書きましたが、これも全く同じパターンでして、
s.hoge = [*1..10].pack('c*')
s.fuga = [*1..10].reverse.pack('c*')
この =
の右側の文字列は、何の変数にも代入されていないので、無慈悲にもGCに回収されてしまうのです。
回避策としては
s.hoge = memo1 = [*1..10].pack('c*')
s.fuga = memo2 = [*1..10].reverse.pack('c*')
のように変数に入れておくというのがあります。
FFIを利用してプログラミングを行う際には、よほどGCに注意しなければならないということを再確認しました。
この記事は以上です。