忘れたときに備えた記録

トップ «前の日記(2009-04-05(Sunday)) 最新 次の日記(2009-05-08(Friday))» 編集
2005|02|03|04|05|06|07|08|09|10|11|12|
2006|01|02|03|04|05|06|07|08|09|10|11|12|
2007|01|02|03|04|05|06|07|08|09|10|11|12|
2008|01|02|03|04|05|06|07|08|09|11|12|
2009|01|02|03|04|05|06|10|12|
2010|06|07|08|12|
2011|07|09|
2012|09|11|
2013|02|03|09|
2015|10|11|
2016|01|08|11|
2017|02|08|10|
2018|11|

2009-05-06(Wednesday)

amazon.rbがSEGVする件

うちではestraier-register.rbを使っていないんですが、amazon.rbでSEGVする問題が発生していました。

ずっと気にはなっていたんてすが、今日ようやく時間ができたので調べてみたのです。

まず根本的な原因なんですが、Ruby-1.8.7にバグがあって、次のコードで落ちます。

#!/usr/bin/ruby
C = nil
o = ""
o.instance_eval("def m; C; end")
o.m
puts 1
o.clone.m
puts 2
~/opt/ruby187/bin/ruby -v ./test
ruby 1.8.7 (2009-04-08 patchlevel 160) [x86_64-linux]
1
(eval):1: [BUG] Segmentation fault
ruby 1.8.7 (2009-04-08 patchlevel 160) [x86_64-linux]

Aborted

ただし、1.8の開発版では、もう直っています

~/opt/ruby18/bin/ruby -v ./test
ruby 1.8.8dev (2009-05-06 revision 23350) [x86_64-linux]
1
2

また、1.9でも発生しないようです。

 ~/opt/ruby19/bin/ruby -v ./test
ruby 1.9.1p5000 (2009-01-28 trunk 21811) [x86_64-linux]
1
2

で、と。とにかく現在の1.8.7では、

  1. オブジェクトに対してinstance_evalで、メソッドを追加する
    • メソッドの中では定数を参照する
  2. そのオブジェクトのクローンを作る
  3. クローンに対して追加したメソッドの呼び出しを行う

という手順でSEGVするわけです。

僕の環境では、estraier-register.rbは使っていないんですが、squeeze.rbを使っています。 この中で

   add_update_proc do
      conf = @conf.clone

として@confのcloneを作り

      def execute
(中略)
               File::open(filename, 'w'){|f| f.write(eval_rhtml)}

@confのcloneを使ってeval_rhtml(中でプラグインを実行)するようになっています。

で、amazon.rbの中では conf.to_native を使っています。

さて、TDiary::Config#to_nativeですが、これは tdiary/lang/ja.rb の中で

def to_native( str, charset = nil )
   begin
      Iconv.conv('utf-8', charset || 'utf-8', str)

といった風に定数 Iconv を呼び出すメソッドを定義して、これをTDiary::Config#initializeが呼び出す #loadでロードしています。この時に、instance_evalを使っています。

      def load
(中略)
         @lang = 'ja' unless @lang
         begin
            instance_eval( File::open( "#{TDiary::PATH}/tdiary/lang/#{@lang}.rb" ){|f| f.read }.untaint, "(tdiary/lang/#{@lang}.rb)", 1 )

というわけで、

  1. conf#to_nativeはinstance_evalで定義されるメソッド
    1. to_nativeの中では定数 Iconv を呼び出し
  2. squeeze.rbでconfをclone
  3. squeeze.rbのeval_rhtmlの中のamazon.rbが、cloneしたconfのto_nativeを呼び出し

のコンボが成立してSEGVするというわけです。

早い話が、squeeze.rbの中で conf=@conf.clone して、クローンのto_nativeを使ったのが原因です。

なので、to_nativeを使っていればamazon.rb以外でもSEGVするし、conf.cloneしていればestraier-register.rbやsqueeze.rb以外でもSEGVするはずです。

また、さっきも書きましたが1.8系列の開発版や1.9系列ではバグが直っているのでそもそも起こりません。

どっとはらいヽ(´ー`)丿

Tags: tDiary

おまけ

あたなたのRubyがamazon.rbでSEGVするか調べるワンライナー

ruby -ve "C=0; o=''; o.instance_eval('def m; C; end'); o.clone.m"

うちで使っているUbuntu 8.10のRubyはダメでした

ruby -ve "C=0; o=''; o.instance_eval('def m; C; end'); o.clone.m"
ruby 1.8.7 (2008-08-11 patchlevel 72) [x86_64-linux]
(eval):1: [BUG] Segmentation fault
ruby 1.8.7 (2008-08-11 patchlevel 72) [x86_64-linux]

Aborted

某所のVine 4.2のは大丈夫でした。

ruby -ve "C=0; o=''; o.instance_eval('def m; C; end'); o.clone.m"
ruby 1.8.5 (2006-08-25) [i386-linux]
本日のツッコミ(全4件) [ツッコミを入れる]
_ takahashim (2009-05-07(Thursday) 18:10)

うちのRuby1.8.7p12ではSEGVしませんでした。<br>ruby 1.8.7 (2008-08-11 patchlevel 72) [i686-linux]<br><br>64bit環境だと問題があるとかでしょうか?

_ hiraku (2009-05-07(Thursday) 18:21)

コメントありがとうございます!<br>上にあげたのは64bit版Ubuntu 8.10のRubyだったんですが、32bitのUbuntu 9.04の<br>ruby 1.8.7 (2008-08-11 patchlevel 72) [i486-linux]<br>でも、SEGVしました(ワンライナー調べ)。<br><br>i486とi686で違ったりするものなんでしょうか?(汗

_ hiraku (2009-05-07(Thursday) 18:27)

今気づきましたが、Debian系列のRuby1.8.7-p72は、すっぴんのp72にその後のパッチをいくつか取り込んでるっぽいので、その辺が原因かもです。<br><br>つまり、p-73からp-160のどこかで入ったのかも

_ yanagisawa (2009-06-13(Saturday) 09:56)

FreeBSD 7.2上でも落ちました。<br>ruby 1.8.7 (2009-04-08 patchlevel 160) [amd64-freebsd7]<br>(eval):1: [BUG] Segmentation fault<br>ruby 1.8.7 (2009-04-08 patchlevel 160) [amd64-freebsd7]<br><br>アボート<br>最近パッケージのバージョンを上げてから落ちるようになったので、p72からp160の間にバグが入ったようですね。

[]