Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SystemStackError at the rack level in Ruby 1.9.2, not 1.8.7

I was brought in on a legacy codebase to upgrade it from Rails 2.4/Ruby 1.8.7 to Rails 3.1/Ruby 1.9.2. While doing this, I found a very interesting problem that took 3 days to try to figure out. I wanted to drop it here both to give it some Google juice for someone else seeing the problem, and to ask the question: Why?

Basically, I was seeing a SystemStackError at the Rack level when running my app. I couldn't get any requests through before the error was caused, and couldn't debug it because my code was never touched. In Development mode, I would be able to see much of the site, then would suddenly get the SystemStackError when the database was hit. So I figured it was something lazy loading.

Switch to production mode, and the exception happens on the first request. The server starts normally, but no requests make it through, and my code wasn't touched.

Fast-forward too many hours, and I tracked down the traceback to a loop in Rails (full gist):

/Users/john/.rvm/gems/ruby-1.9.2-p320@qstream-ruby19/gems/actionpack-3.1.6/lib/action_dispatch/routing/url_for.rb:102:in `initialize' 
/Users/john/.rvm/gems/ruby-1.9.2-p320@qstream-ruby19/gems/actionpack-3.1.6/lib/action_controller/metal.rb:140:in `initialize' 
/Users/john/.rvm/gems/ruby-1.9.2-p320@qstream-ruby19/gems/actionpack-3.1.6/lib/abstract_controller/rendering.rb:74:in `initialize' 
/Users/john/.rvm/gems/ruby-1.9.2-p320@qstream-ruby19/gems/actionpack-3.1.6/lib/abstract_controller/layouts.rb:301:in `initialize' 
/Users/john/.rvm/gems/ruby-1.9.2-p320@qstream-ruby19/gems/actionpack-3.1.6/lib/action_dispatch/routing/url_for.rb:103:in `initialize' 
/Users/john/.rvm/gems/ruby-1.9.2-p320@qstream-ruby19/gems/actionpack-3.1.6/lib/action_controller/metal.rb:140:in `initialize' 
/Users/john/.rvm/gems/ruby-1.9.2-p320@qstream-ruby19/gems/actionpack-3.1.6/lib/abstract_controller/rendering.rb:74:in `initialize' 
/Users/john/.rvm/gems/ruby-1.9.2-p320@qstream-ruby19/gems/actionpack-3.1.6/lib/abstract_controller/layouts.rb:301:in `initialize' 
/Users/john/.rvm/gems/ruby-1.9.2-p320@qstream-ruby19/gems/actionpack-3.1.6/lib/action_dispatch/routing/url_for.rb:103:in `initialize' 
/Users/john/.rvm/gems/ruby-1.9.2-p320@qstream-ruby19/gems/actionpack-3.1.6/lib/action_controller/metal.rb:140:in `initialize' 
/Users/john/.rvm/gems/ruby-1.9.2-p320@qstream-ruby19/gems/actionpack-3.1.6/lib/abstract_controller/rendering.rb:74:in `initialize' 
/Users/john/.rvm/gems/ruby-1.9.2-p320@qstream-ruby19/gems/actionpack-3.1.6/lib/abstract_controller/layouts.rb:301:in `initialize' 
/Users/john/.rvm/gems/ruby-1.9.2-p320@qstream-ruby19/gems/actionpack-3.1.6/lib/action_dispatch/routing/url_for.rb:103:in `initialize' 
/Users/john/.rvm/gems/ruby-1.9.2-p320@qstream-ruby19/gems/actionpack-3.1.6/lib/action_controller/metal.rb:140:in `initialize' 
/Users/john/.rvm/gems/ruby-1.9.2-p320@qstream-ruby19/gems/actionpack-3.1.6/lib/abstract_controller/rendering.rb:74:in `initialize' 
/Users/john/.rvm/gems/ruby-1.9.2-p320@qstream-ruby19/gems/actionpack-3.1.6/lib/abstract_controller/layouts.rb:301:in `initialize' 
/Users/john/.rvm/gems/ruby-1.9.2-p320@qstream-ruby19/gems/actionpack-3.1.6/lib/action_dispatch/routing/url_for.rb:103:in `initialize' 
/Users/john/.rvm/gems/ruby-1.9.2-p320@qstream-ruby19/gems/actionpack-3.1.6/lib/action_controller/metal.rb:238:in `new' 
/Users/john/.rvm/gems/ruby-1.9.2-p320@qstream-ruby19/gems/actionpack-3.1.6/lib/action_controller/metal.rb:238:in `block in action' 
/Users/john/.rvm/gems/ruby-1.9.2-p320@qstream-ruby19/gems/actionpack-3.1.6/lib/action_dispatch/routing/route_set.rb:71:in `call' 
/Users/john/.rvm/gems/ruby-1.9.2-p320@qstream-ruby19/gems/actionpack-3.1.6/lib/action_dispatch/routing/route_set.rb:71:in `dispatch' 
/Users/john/.rvm/gems/ruby-1.9.2-p320@qstream-ruby19/gems/actionpack-3.1.6/lib/action_dispatch/routing/route_set.rb:35:in `call' 
/Users/john/.rvm/gems/ruby-1.9.2-p320@qstream-ruby19/gems/rack-mount-0.8.3/lib/rack/mount/route_set.rb:152:in `block in call' 
/Users/john/.rvm/gems/ruby-1.9.2-p320@qstream-ruby19/gems/rack-mount-0.8.3/lib/rack/mount/code_generation.rb:96:in `block in recognize' 
/Users/john/.rvm/gems/ruby-1.9.2-p320@qstream-ruby19/gems/rack-mount-0.8.3/lib/rack/mount/code_generation.rb:68:in `optimized_each' 
/Users/john/.rvm/gems/ruby-1.9.2-p320@qstream-ruby19/gems/rack-mount-0.8.3/lib/rack/mount/code_generation.rb:95:in `recognize' 
/Users/john/.rvm/gems/ruby-1.9.2-p320@qstream-ruby19/gems/rack-mount-0.8.3/lib/rack/mount/route_set.rb:141:in `call' 
/Users/john/.rvm/gems/ruby-1.9.2-p320@qstream-ruby19/gems/actionpack-3.1.6/lib/action_dispatch/routing/route_set.rb:538:in `call' 
/Users/john/.rvm/gems/ruby-1.9.2-p320@qstream-ruby19/gems/omniauth-1.1.0/lib/omniauth/builder.rb:48:in `call'
...

What we see here is the system cycling from metal.rb to url_for.rb to layouts.rb to rendering.rb to metal.rb to url_for.rb, etc

After considerable effort, I tracked this down to the following line at the top of a model file (like so):

include ActionView::Helpers::UrlHelpers

Note, this is not inside the class, it is at the module level.

The interesting thing is that this works in Ruby 1.8.7 but causes a SystemStackError in Ruby 1.9.2.

I have created a Github repository illustrating this behavior.

If you grab this repository, and run the ruby18 branch, you can load a page. If you run the ruby19 branch, you get a SystemStackError on any request (any request where Widget is loaded, run it in production and it won't be lazy loaded).

So, does anyone know why?

I mean, I imagine it has something to do with the way Ruby 1.9 loads modules, since it doesn't seem to be a problem caused by the Rails core. My main concern is a question of whether this is just an esoteric issue caused by lazy programming practices in the codebase, or if it is a pointer to a deeper problem, either in Ruby or Rails.

like image 775
JohnMetta Avatar asked Nov 14 '22 03:11

JohnMetta


1 Answers

This looks like Bug 3144, saying to reference the helper directly.

Rails.application.routes.url_helpers
like image 80
Jeremy Peterson Avatar answered Dec 05 '22 04:12

Jeremy Peterson