Fri 18 May 2007 09:02:48 PM UTC, original submission:
BUG: severe
VERSION: 0.6.0.20070509-1
PROBLEM: recursion and crash if message A is related to message B and
message B is related to message A. This occurred on a live site! The error
causes a crash (with error hash given to the user) after the second relation
is voted on, or when trying to load the frontpage.
The recursion probably did not exist in pre-20070501, since the recursive
A->B->A relationship existed in the database without causing errors in
the pages rendered through apache pre-20070501.
DIAGNOSIS:
Key lines excerpted from the three routines involved in the loop.
models/focus.rb:
class Focus
def initialize(request, id=nil, related=nil) # todo: unit-test this beast
if id # existing resource
@resource = Resource.new(request, id)
components/resource.rb:
class Resource
def initialize(request, id)
@component = instance_eval(@type + 'Component.new(@request, @id)')
class MessageComponent < ResourceComponent
def initialize(request, id)
@info = message_info(@message, :list)
helpers/message_helper.rb:
module MessageHelper
def message_info(message, mode)
focuses = focus_line(message.id, message.focuses.collect {|f|
Focus.new(@request, f, message.id)
})
PROPOSED SOLUTION:
An anti-recursion counter could probably be placed in any of these three
files. MessageHelper::message_info seemed a good place, in order to
avoid intervening in the more central parts of the whole system. The patch
is below.
--- /tmp/s070509/samizdat/lib/samizdat/helpers/message_helper.rb 2007-04-30 23:46:20.000000000 +0200
+++ /usr/lib/ruby/1.8/samizdat/helpers/message_helper.rb 2007-05-18 22:44:35.016692272 +0200
@@ -13,6 +13,8 @@
module MessageHelper
include ApplicationHelper
+ @@recursion_depth = 0
+
# render link to full message
#
def full_message_href(id)
@@ -61,9 +63,18 @@
message.translations.sort_by {|l,m,r| -r.to_f }.collect {|l,m,r|
%{<a href="#{m}">#{l}</a>}
}.join(' ') if message.translations.to_a.size > 0
- focuses = focus_line(message.id, message.focuses.collect {|f|
- Focus.new(@request, f, message.id)
- })
+
+
+ @@recursion_depth += 1
+ if @@recursion_depth <= 1
+ focuses = focus_line(message.id, message.focuses.collect {|f|
+ Focus.new(@request, f, message.id)
+ })
+ else
+ focuses = nil
+ end
+ @@recursion_depth = 0
+
hidden = _('hidden') if message.hidden?
[ sprintf(_('by %s on %s'), creator, date.to_s),
|