yamlでアンカーにエイリアス

そういえば、Rubyがまだ1.9.1だったなーという事を思い出したのでアップデートをしてみた。
RubyWorldConference2010の中でYAMLのパーサーががsyckからpsyckに変わったらしいという事を聞きました。
syckの実装者が失踪してしまったからだとかなんとか。

昔、syckでハマった事がありますが、どうなったのかなー?

アンカーにエイリアス

  • 昔ハマったというのは、アンカーにエイリアスを貼って、GCを走らせるとエラーになる(rescueでも拾えない)というものです。
    • GCが走らない限りは、通常どおりつかえる。
    • 多分、サンプルコードを見た方が早いです。
ハマり方

アンカーにエイリアスを貼ります。

sample1:
  - &figure1
    arg1: "test1"
    arg2: "test2"
  - &figure2 *figure1
  • sample.rb
require 'yaml'

a = YAML.load_file("sample.yaml")
p a

puts "=== start ==="
GC.start
puts "=== end ==="
  • 実行
ionis@ubuntu:~/workspace$ ruby -v
ruby 1.9.2p0 (2010-08-18 revision 29036) [i686-linux]

ionis@ubuntu:~/workspace$ ruby sample.rb
{"sample1"=>[{"arg1"=>"test1", "arg2"=>"test2"}, {"arg1"=>"test1", "arg2"=>"test2"}]}
=== start ===
glibc detected *** ruby: double free or corruption (fasttop): 0x09e81d50 ***
======= Backtrace: ========= /lib/tls/i686/cmov/libc.so.6(+0x6b591)[0x1a1591] /lib/tls/i686/cmov/libc.so.6(+0x6cde8)[0x1a2de8] /lib/tls/i686/cmov/libc.so.6(cfree+0x6d)[0x1a5ecd] /usr/local/lib/ruby/1.9.1/i686-linux/syck.so(syck_free_node+0x56)[0xe31cf6] /usr/local/lib/ruby/1.9.1/i686-linux/syck.so(syck_st_free_nodes+0x22)[0xe3e472] /usr/local/lib/libruby.so.1.9(st_foreach+0xb1)[0x3db951] /usr/local/lib/ruby/1.9.1/i686-linux/syck.so(syck_st_free+0x37)[0xe3e3f7] /usr/local/lib/ruby/1.9.1/i686-linux/syck.so(syck_free_parser+0x51)[0xe3ea21] /usr/local/lib/ruby/1.9.1/i686-linux/syck.so(rb_syck_free_parser+0x38)[0xe3c518] /usr/local/lib/libruby.so.1.9(rb_gc+0xc2)[0x339612] /usr/local/lib/libruby.so.1.9(rb_gc_start+0x17)[0x339797] /usr/local/lib/libruby.so.1.9(+0x16790d)[0x43190d] /usr/local/lib/libruby.so.1.9(+0x178277)[0x442277] /usr/local/lib/libruby.so.1.9(+0x16d253)[0x437253] /usr/local/lib/libruby.so.1.9(+0x172820)[0x43c820] /usr/local/lib/libruby.so.1.9(rb_iseq_eval_main+0x1e3)[0x43cc43] /usr/local/lib/libruby.so.1.9(+0x58a8a)[0x322a8a] /usr/local/lib/libruby.so.1.9(ruby_exec_node+0x25)[0x322ac5] /usr/local/lib/libruby.so.1.9(ruby_run_node+0x35)[0x3242d5] ruby(main+0x68)[0x80487d8] /lib/tls/i686/cmov/libc.so.6(__libc_start_main+0xe6)[0x14cbd6] ruby[0x80486d1]
実はGC.startがなくても、上記sample.rbの場合はこのエラーが出ますけどね。 このエラーは、GCが走る際に起きるっぽいです。 なので、以下のようなプログラムにすると、CTRL+Cを押すまで、特にエラーは出ないです。
  • sample2.rb
require 'yaml'

a = YAML.load_file("sample.yaml")

puts "=== start ==="
loop do
  print a['sample1'][1], " \r"
end
puts "=== end ==="
しかし、ここで、ふと気づく
/usr/local/lib/ruby/1.9.1/i686-linux/syck.so(syck_free_node+0x56)[0xe31cf6]
・・・もしかして、僕Ruby1.9.2のインストールに失敗してない?(=”=;; ま、まぁ、ruby1.8.6とかIronRuby1.0で発生するのは確認しているので、その辺を使っている方はお気をつけください。 ・・・「複数アンカーなんて作らないよ!」と言われれば、それまでなんですけどね! えぇ・・・私の書き方が悪いだけですよ!(凹 ちなみに、JRubyではこのエラーは出なかったはずです。 また、Ruby1.8.6とIronRubyでは表示される内容が微妙に違ったハズ・・・(ちょっと記憶が曖昧です。) なお、おそらくこのバグはこのチケットだと思われます。