"Out of memory" error in active_record_runtime()

I’ve come across an apparent bug in Rail 1.2.6 while going through the
Depot sample code in “Agile Web D…”. I’ve done some
searches, and couldn’t find anything referencing this problem.

I’ve patched around it, but not sure if what I have is a real fix, and
have never submitted a bug fix to the Rails community before, so thought
I’d start here.

Not sure if this is actually a bug in Rails or if it lives deeper in
Ruby. It should be easy to reproduce, since it manifests itself in
Depot.

I’d previously run through all the the Depot code, and written a Rails
application using Rails 1.1.9. I wanted to dust-off my Rails and update
the app, so I first updated to Rails 2.2.6 I am running Ruby 1.8.5
(2007-09-24 patchlevel 114) [x86_64-linux] which is the current Ruby in
the Fedora Core 6 repository.

Note that I didn’t try to upgrade my old Depot application, as my goal
was to review the basics. I started from scratch, so no issues with
incompatibility of previously-generated code.

The bug shows itself in Iteration C4, upon pressing the “Clear Cart”
button:


NoMemoryError in StoreController#empty_cart

negative allocation size (or too big)

RAILS_ROOT: ./script/…/config/…
Application Trace | Framework Trace | Full Trace

/usr/lib64/ruby/gems/1.8/gems/actionpack-1.13.6/lib/action_controller/benchmarking.rb:86:in
sprintf' /usr/lib64/ruby/gems/1.8/gems/actionpack-1.13.6/lib/action_controller/benchmarking.rb:86:inactive_record_runtime’

Here’s the function that is failing, along with my fix. The
commented-out line is the original code - the next line is my fix:

  def active_record_runtime(runtime)
    db_runtime    = ActiveRecord::Base.connection.reset_runtime
    db_runtime    += @db_rt_before_render if @db_rt_before_render
    db_runtime    += @db_rt_after_render if @db_rt_after_render
    db_percentage = (db_runtime * 100) / runtime
    #" | DB: #{sprintf("%.5f", db_runtime)} (#{sprintf("%d",

db_percentage)}%)"
" DB: #{sprintf("%.5f", db_runtime)} (#{sprintf("%.f",
db_percentage)}%)"
end
end
end

The sprintf with the %d format specification is throwing this error.
Replacing it with a %.f works-around the problem, but, as I said above,
I suspect that I might just be wallpapering-over some deeper problem in
sprintf.

With the patch in place, I discovered that in this case, the value of
db_runtime is 0.0, and thus db_percentage as well is 0.0. Prior to this
point in Depot, I apparently hadn’t encountered another 0.0 value for
db_runtime. Of course, this is because there’s no database access - it’s
just the first place working through the example that a page does no
database access.

So, I boiled this down to an incredibly-simple test case:

[jon@colossus ~]$ irb
irb(main):001:0> sprintf("%d", 0.0)
(irb):1:in sprintf': negative allocation size (or too big) (NoMemoryError) from (irb):1:inirb_binding’
from /usr/lib/ruby/1.8/irb/workspace.rb:52:in `irb_binding’
from /usr/lib/ruby/1.8/irb/workspace.rb:52

Now, I’m not sure if this is valid behavior or not. Is %d not supposed
to be used on floating-point values? It seems to fail only for a
floating-point value of 0.0. An integer 0 is fine.

Jon Tara wrote:

I’d previously run through all the the Depot code, and written a Rails
application using Rails 1.1.9. I wanted to dust-off my Rails and update
the app, so I first updated to Rails 2.2.6 I am running Ruby 1.8.5
(2007-09-24 patchlevel 114) [x86_64-linux] which is the current Ruby in
the Fedora Core 6 repository.

NoMemoryError in StoreController#empty_cart

negative allocation size (or too big)

http://groups.google.com/group/rubyonrails-talk/browse_thread/thread/da3d6c49bdaf984c


We develop, watch us RoR, in numbers too big to ignore.