MacOS – Ruby 1.9.3’s infamous OS X OpenSSL segfault in http.rb:799

macosopensslrailsruby

[Post shortened and updated with an answer.]

Ruby 1.9.3 compiled on OS X 10.7.4 with MacPorts crashes in my Rails apps when using SSL in http.rb, e.g. when authenticating to Facebook:

(facebook) Callback phase initiated.
/opt/local/lib/ruby1.9/1.9.1/net/http.rb:799: [BUG] Segmentation fault
ruby 1.9.3p194 (2012-04-20 revision 35410) [x86_64-darwin11]

Note: This is a real solution to the segfault problem, not a try-my-favorite-alternative-ruby-installer-du-jour solution. I didn't want to modify half my system on half a dozen devel and production machines by installing RVM, rbenv, Homebrew or anything else. I also want to show how I found the problem since this can occur with any Ruby installer.

Some things I noted by trial and error:

  • Compiling OpenSSL and Ruby using --with-openssl-dir=/usr or ..=/opt/local did not help.
  • After recompiling Ruby 1.9 using /opt/local as openssl-dir, other than in numerous other posts on the web, I could run SSL based connects from the command line fine. However, SSL connects in my Rails projects were still crashing.
  • The crash backtrace which OS X saves in /Library/Logs/CrashReporter contained traces of libssl.1.0.0.dylib (MacPorts) and libssl.0.9.8.dylib (OS X). But all my MacPorts files were linked against OpenSSL 1.0.x. (find /opt/local -iname "*.dylib" | xargs otool -L is your friend!)
  • This occured only on my live apps. Not on virgin new apps.
  • This occured only when using the pg Postgres gem which contains native extensions.

Looking at the PG gem's bundle:

$ otool -L /opt/local/lib/ruby1.9/gems/1.9.1/gems/pg-0.14.1/lib/pg_ext.bundle 
/opt/local/lib/ruby1.9/gems/1.9.1/gems/pg-0.14.1/lib/pg_ext.bundle:
/opt/local/lib/libruby.1.9.1.dylib (compatibility version 1.9.1, current version 1.9.1)
/usr/lib/libpq.5.dylib (compatibility version 5.0.0, current version 5.3.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 159.1.0)
/usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0)

The PG gem does not link against MacPorts's libpq! And:

Jens ~/Sites/testapp$ otool -L /usr/lib/libpq.5.dylib
/usr/lib/libpq.5.dylib:
/usr/lib/libpq.5.dylib (compatibility version 5.0.0, current version 5.3.0)
/usr/lib/libssl.0.9.8.dylib (compatibility version 0.9.8, current version 44.0.0)
/usr/lib/libcrypto.0.9.8.dylib (compatibility version 0.9.8, current version 44.0.0)
    (...)

… OSX's libpq (of course!) links against OS X's libssl and libcrypto. Bingo!

Solution: RTFM! PG's README-OS_X says:

If you need a custom installation of PostgreSQL, you should ensure that you either compile it against the same version of OpenSSL as the OpenSSL extension of the Ruby you'll be using, or compile it without SSL support. If you fail to do this, you will likely see segfaults …

So:

sudo gem install pg -- --with-pg-config=/opt/local/lib/postgresql83/bin/pg_config

Bingo, problem solved.

$ bundle exec rails runner "require 'net/http'; require 'net/https'; h=Net::HTTP.new('gmail.com', 443); h.use_ssl=true; puts h.get('/');"
#<Net::HTTPMovedPermanently:0x007fe48d5590a0>

If your bundle does not reference the current latest pg gem version, then you'll need to specify the version when reinstalling, e.g.

gem install pg -v 0.13.2 -- --with-pg-config=/opt/local/lib/postgresql91/bin/pg_config

Best Answer

See above - the PG gem was the culprit. Apparently, it automatically compiles against the OS X built-in Postgres (9.0) libraries, which are of course compiled against OS X builtin OpenSSL.

Once I found this to be the reason, the fix was trivial. No need to install RVM, rbenv, Homebrew or anything else. Just recompile the PG gem ...