Paradigm Shift Design

ISHITOYA Kentaro's blog.

OSX+PostgreSQL+Railsな環境でhttpsにアクセスするとSegmentation Faultする

前回のエントリではWindowsがどうのと言っていましたが、TestやWEBrickの起動が遅すぎて話にならないのでMacに環境を再構築しました。
PHPもとても遅いのだけれど、それはOSのFile I/Oの速度が大きく影響しているっぽいです。


それはさておき、OSXでWEBrickを立ち上げてTwitterにアクセスしたところ、

/Users/kent/.rvm/rubies/ruby-1.9.2-p180/lib/ruby/1.9.1/net/http.rb:678: [BUG] Segmentation fault


というエラーが出てきました*1。ソースをみるとhttpsソケットを作ってconnectしようとして落ちているようです。Windowsでは正しく動作していたプログラムだったので、理由がわからず。Rubyの所為かと思ってp0からheadリビジョンまで入れて試してみましたが何も変わらず。むしろ何も変わらないので、ほかに原因があるんだなとおもって探していると、
[Ruby 1.9-Bug#4373][Open] http.rb:677: [BUG] Segmentation fault - Ruby Forum
に行き当たりました。というか、これしか情報源ないの?的な。


結論から言うと、
portsやOne Click InstallerでインストールしたPostgreSQLが使っているOpenSSLのバージョンが、Rubyの使っているものよりも古くてかつ先に読み込まれているので、RubyからTwitterHTTPSで提供されているサービスにアクセスしようとしたときに、落ちる。
ということのようです。


上のサイトにあるようにして、使っているライブラリを確認してみると

rails console
ruby-1.9.2-p180 :001 > require 'openssl'
 => nil 
ruby-1.9.2-p180 :002 > system "otool -L #{$LOADED_FEATURES.grep(/openssl.bundle/).join (' ')}"

とするとRubyで利用しようとしている読み込まれているopensslのバージョンがわかります。結果は

/Users/kent/.rvm/rubies/ruby-1.9.2-p180/lib/ruby/1.9.1/x86_64-darwin10.7.0/openssl.bundle:
        /Users/kent/.rvm/rubies/ruby-1.9.2-p180/lib/libruby.1.9.1.dylib (compatibility version 1.9.1, current version 1.9.1)
        /usr/lib/libssl.0.9.8.dylib (compatibility version 0.9.8, current version 0.9.8)
        /usr/lib/libcrypto.0.9.8.dylib (compatibility version 0.9.8, current version 0.9.8)
        /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 125.2.10)
        /usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 227.0.0)
 => true

とでて、0.9.8を読み込もうとしています。

対するPostgreSQLは、

bash-3.2$ otool -L /Library/PostgreSQL/9.0/lib/libpq.dylib 
/Library/PostgreSQL/9.0/lib/libpq.dylib:
  libpq.5.dylib (compatibility version 5.0.0, current version 5.3.0)
  /usr/lib/libssl.0.9.7.dylib (compatibility version 0.9.7, current version 0.9.7)
  /usr/lib/libcrypto.0.9.7.dylib (compatibility version 0.9.7, current version 0.9.7)
  /System/Library/Frameworks/Kerberos.framework/Versions/A/Kerberos (compatibility version 5.0.0, current version 5.0.0)
  /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 111.1.4)

で、0.9.7でした。この違いがエラーを引き起こしているようです。


で、解決策ですが、

  1. developmentではsqlite3を使う
  2. 自分でPostgreSQLソースコードを持ってきてインストールする

1は後ろ向きですが、まぁSQLのチューニングが必要だとかの特段の理由がなければ開発環境でPostgreSQLを使う理由はないですし。それでもいいかなと思います。
2はPostgreSQLのサイトからtarボールを持ってきてconfigure/make/make installで、デフォルトの位置にインストールされたなら

gem install pg -- --with-pg-dir=/usr/local/pgsql/

とすればいいです。デフォルトでconfigureするとwithout opensslなので、opensslサポートが必要ならそのようにconfigureすればいいです。
ただ、localhostとの通信にopenssl使う理由もわからないので、必要ないでしょう。


しかし、本当にRuby界隈のみなさんは、PostgreSQL使ってないんだなと感じた出来事でした。
いや、前回の記事ではWindowsが悪いんだ!って言ってたけど、PostgreSQLが過疎ってるだけでした。PostgreSQLいいよ!Postgre!


という訳で、エラーエントリでした。

*1:少し前のバージョンのRubyだとhttp.rb:677、いずれにしてもconnectメソッド内