smtp.rb:14: [BUG] Segmentation fault

I just fixed a problem that I was running into on my Mac development machine. Things were running fine in my production environment (Heroku) but when I tried to send mail locally, I got the following error:

> rails c        
Loading development environment (Rails 3.0.8)
ree-1.8.7-head :001 > MyMailer.daily_email.deliver
~/.rvm/gems/ree-1.8.7-head@mygemset/gems/mail-2.2.19/
  lib/mail/core_extensions/smtp.rb:14: [BUG] Segmentation fault
ruby 1.8.7 (2011-02-18 patchlevel 334) [i686-darwin10.7.0]
zsh: abort      rails c

Hmm. I indeed use SMTP to send mail, but nothing too crazy. Plus it worked in production, and up until recently it was working locally. For more background, I was also using the Sendgrid plugin.

The first thing I thought of was googling for the error message that I found (“mail-2.2.19/lib/mail/core_extensions/smtp.rb:14”). This produced some useful links, but nothing that fixed the problem.

One option was to disregard the error, but I was trying to fix some email layout issues and it would have lengthened my development feedback cycle considerably (push to production, then test manually.)

Next, I thought of upgrading the mail gem because perhaps there was a patch of some sort that fixed the problem that I ran into. However, I was using the ActionMailer gem, which required a certain version of mail that was the same in the version of Rails I was using (3.0.8) and latest (3.0.9). So this was not a viable solution path. I took a look at the offending Net::SMTP line (which I probably should have done a bit earlier) and there was nothing obviously wrong with it. The whole file looked like:

module Net
  class SMTP
    # This is a backport of r30294 from ruby trunk because of a bug in net/smtp.
    # http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=30294
    #
    # Fixed in what will be Ruby 1.9.3 - tlsconnect also does not exist in some early versions of ruby
    remove_method :tlsconnect if defined?(Net::SMTP.new.tlsconnect)

    def tlsconnect(s)
      verified = false
      s = OpenSSL::SSL::SSLSocket.new s, @ssl_context
      logging "TLS connection started"
      s.sync_close = true
      s.connect                **************** crash line
      if @ssl_context.verify_mode != OpenSSL::SSL::VERIFY_NONE
        s.post_connection_check(@address)
      end
      verified = true
      s
    ensure
      s.close unless verified
    end
  end
end

I then made a more general search for “ruby net/smtp segmentation fault” and about half the page down ran into this helpful post. It’s pretty lengthy and the bug submitter is a champ for following through with it and providing as much detail as he did. I feel like I understand the whole Ruby / OpenSSL situation a lot better after reading through it. Plus, figured out where Ruby crash logs are on the computer. I ran into this problem before, but couldn’t figure out a good solution, and then it went away inexplicably (not much fodder for a writeup.)

Anyway, a comment toward the end of that post led me in the right direction. I ended up adding the following to my .zshrc for the Mac platform after testing the export manually.

This fixed the problem, and mail went through as expected in the development environment. My understanding is that Ruby was using a buggy version of OpenSSL, and this points it to use the correct version.

For more info on how RUBYOPT works, check out this post on RUBYOPT.

Categories: development

« The State of Ruby and Testing Using Scalpel to Recover Lost Data in Ubuntu »

Comments