Webrick gets stuck with certain exceptions?

I've written a servlet using webrick. I've written it badly. Some
exceptions (particularly those relating to missing methods or missing
variables) causes the servlet thread to consume ever larger amounts of
memory and not return anything. Turning on tracer shows me that after
the exception is thrown the webrick thread gets stuck, performing this
for ever:

....
#2:/opt/local/lib/ruby/1.8/webrick/log.rb:64:Fixnum:>:
"#{arg.class}: #{arg.message}\n\t" <<
#2:/opt/local/lib/ruby/1.8/webrick/log.rb:64:Fixnum:<:
"#{arg.class}: #{arg.message}\n\t" <<
#2:/opt/local/lib/ruby/1.8/webrick/log.rb:64:Fixnum:>:
"#{arg.class}: #{arg.message}\n\t" <<
#2:/opt/local/lib/ruby/1.8/webrick/log.rb:64:Fixnum:<:
"#{arg.class}: #{arg.message}\n\t" <<
.....

I can fix the underlying error. But does anyone have any thoughts as
to what I might have done wrong to cause these exceptions to jam
webrick up? (I've put the bit leading up to the error below)

Many thanks

Tom

(running ruby 1.8.1 (2003-12-25) [powerpc-darwin])

#2:soks2.rb:516:NameError:>: @wiki.revise( pagename,
upload( "attachment/#{request.query['file'].filename}",
request.query['file'] ) , author, @wiki.content_type( pagename ) )
#2:soks2.rb:516:NameError:<: @wiki.revise( pagename,
upload( "attachment/#{request.query['file'].filename}",
request.query['file'] ) , author, @wiki.content_type( pagename ) )
#2:soks2.rb:516:Exception:>: @wiki.revise( pagename,
upload( "attachment/#{request.query['file'].filename}",
request.query['file'] ) , author, @wiki.content_type( pagename ) )
#2:soks2.rb:516:Exception:<: @wiki.revise( pagename,
upload( "attachment/#{request.query['file'].filename}",
request.query['file'] ) , author, @wiki.content_type( pagename ) )
#2:soks2.rb:516:Exception:>: @wiki.revise( pagename,
upload( "attachment/#{request.query['file'].filename}",
request.query['file'] ) , author, @wiki.content_type( pagename ) )
#2:soks2.rb:516:Exception:<: @wiki.revise( pagename,
upload( "attachment/#{request.query['file'].filename}",
request.query['file'] ) , author, @wiki.content_type( pagename ) )
#2:soks2.rb:516:WikiServlet:: @wiki.revise( pagename,
upload( "attachment/#{request.query['file'].filename}",
request.query['file'] ) , author, @wiki.content_type( pagename ) )
#2:soks2.rb:516:Kernel:<: @wiki.revise( pagename,
upload( "attachment/#{request.query['file'].filename}",
request.query['file'] ) , author, @wiki.content_type( pagename ) )
#2:soks2.rb:488:WikiServlet:<: self.send( verb , request,
response, pagename, request.user)
#2:soks2.rb:488:Kernel:<: self.send( verb , request,
response, pagename, request.user)
#2:/opt/local/lib/ruby/1.8/webrick/httpserver.rb:54:WikiServlet:<:
      service(req, res)
#2:/opt/local/lib/ruby/1.8/webrick/server.rb:150:WEBrick::HTTPServer:<:
          block ? block.call(sock) : run(sock)
#2:/opt/local/lib/ruby/1.8/webrick/httpserver.rb:55:Module:>:
rescue HTTPStatus::EOFError, HTTPStatus::RequestTimeout => ex
#2:/opt/local/lib/ruby/1.8/webrick/httpserver.rb:55:Module:<:
rescue HTTPStatus::EOFError, HTTPStatus::RequestTimeout => ex
#2:/opt/local/lib/ruby/1.8/webrick/httpserver.rb:55:Module:>:
rescue HTTPStatus::EOFError, HTTPStatus::RequestTimeout => ex
#2:/opt/local/lib/ruby/1.8/webrick/httpserver.rb:55:Module:<:
rescue HTTPStatus::EOFError, HTTPStatus::RequestTimeout => ex
#2:/opt/local/lib/ruby/1.8/webrick/httpserver.rb:57:Module:>:
rescue HTTPStatus::Error => ex
#2:/opt/local/lib/ruby/1.8/webrick/httpserver.rb:57:Module:<:
rescue HTTPStatus::Error => ex
#2:/opt/local/lib/ruby/1.8/webrick/httpserver.rb:59:Module:>:
rescue HTTPStatus::Status => ex
#2:/opt/local/lib/ruby/1.8/webrick/httpserver.rb:59:Module:<:
rescue HTTPStatus::Status => ex
#2:/opt/local/lib/ruby/1.8/webrick/httpserver.rb:61:Module:>:
rescue StandardError => ex
#2:/opt/local/lib/ruby/1.8/webrick/httpserver.rb:61:Module:<:
rescue StandardError => ex
#2:/opt/local/lib/ruby/1.8/webrick/httpserver.rb:62:WEBrick::HTTPServer:-:
          @logger.error(ex)
#2:/opt/local/lib/ruby/1.8/webrick/log.rb:49:WEBrick::BasicLog:>:
def error(msg) log(ERROR, "ERROR " << format(msg)); end
#2:/opt/local/lib/ruby/1.8/webrick/log.rb:49:WEBrick::BasicLog:-:
def error(msg) log(ERROR, "ERROR " << format(msg)); end
#2:/opt/local/lib/ruby/1.8/webrick/log.rb:62:WEBrick::BasicLog:>:
def format(arg)
#2:/opt/local/lib/ruby/1.8/webrick/log.rb:63:WEBrick::BasicLog:-:
str = if arg.is_a?(Exception)
#2:/opt/local/lib/ruby/1.8/webrick/log.rb:63:WEBrick::BasicLog:-:
str = if arg.is_a?(Exception)
#2:/opt/local/lib/ruby/1.8/webrick/log.rb:63:Kernel:>: str = if
arg.is_a?(Exception)
#2:/opt/local/lib/ruby/1.8/webrick/log.rb:63:Kernel:<: str = if
arg.is_a?(Exception)
#2:/opt/local/lib/ruby/1.8/webrick/log.rb:65:WEBrick::BasicLog:-:
   arg.backtrace.join("\n\t") << "\n"
#2:/opt/local/lib/ruby/1.8/webrick/log.rb:64:Kernel:>:
"#{arg.class}: #{arg.message}\n\t" <<
#2:/opt/local/lib/ruby/1.8/webrick/log.rb:64:Kernel:<:
"#{arg.class}: #{arg.message}\n\t" <<
#2:/opt/local/lib/ruby/1.8/webrick/log.rb:64:Module:>:
"#{arg.class}: #{arg.message}\n\t" <<
#2:/opt/local/lib/ruby/1.8/webrick/log.rb:64:Module:<:
"#{arg.class}: #{arg.message}\n\t" <<
#2:/opt/local/lib/ruby/1.8/webrick/log.rb:64:Exception:>:
"#{arg.class}: #{arg.message}\n\t" <<
#2:/opt/local/lib/ruby/1.8/webrick/log.rb:64:NameError:>:
"#{arg.class}: #{arg.message}\n\t" <<
#2:/opt/local/lib/ruby/1.8/webrick/log.rb:64:Kernel:>:
"#{arg.class}: #{arg.message}\n\t" <<
#2:/opt/local/lib/ruby/1.8/webrick/log.rb:64:Kernel:>:
"#{arg.class}: #{arg.message}\n\t" <<
#2:/opt/local/lib/ruby/1.8/webrick/log.rb:64:Fixnum:>:
"#{arg.class}: #{arg.message}\n\t" <<
#2:/opt/local/lib/ruby/1.8/webrick/log.rb:64:Fixnum:<:
"#{arg.class}: #{arg.message}\n\t" <<

I'm not sure at all if this is it, but there was a bug in ruby 1.8
(fixed, I think, in 1.8.1 or 1.8.2) that caused very deep recursion in
some exceptions. Some suggestions:

      * If you can, try it under 1.8.2; I wouldn't recommend blindly
        upgrading as there are some semantics changes between 1.8 and
        1.8.1 that (at least for me) broke things. But it is definitely
        worth testing
      * Search the change logs for the bug. If you compiled ruby from
        source (or can) you may be able to back port the patch.

Let us know what you find out; I'll let you know if I think of anything
further. If you can't try either of the things I've suggested, give a
bit more background information about the environment & I'll take a look
at it this evening.

-- Markus

···

On Thu, 2004-09-30 at 10:15, Tom Counsell wrote:

I've written a servlet using webrick. I've written it badly. Some
exceptions (particularly those relating to missing methods or missing
variables) causes the servlet thread to consume ever larger amounts of
memory and not return anything. Turning on tracer shows me that after
the exception is thrown the webrick thread gets stuck, performing this
for ever:

....
#2:/opt/local/lib/ruby/1.8/webrick/log.rb:64:Fixnum:>:
"#{arg.class}: #{arg.message}\n\t" <<
#2:/opt/local/lib/ruby/1.8/webrick/log.rb:64:Fixnum:<:
"#{arg.class}: #{arg.message}\n\t" <<
#2:/opt/local/lib/ruby/1.8/webrick/log.rb:64:Fixnum:>:
"#{arg.class}: #{arg.message}\n\t" <<
#2:/opt/local/lib/ruby/1.8/webrick/log.rb:64:Fixnum:<:
"#{arg.class}: #{arg.message}\n\t" <<
.....

I can fix the underlying error. But does anyone have any thoughts as
to what I might have done wrong to cause these exceptions to jam
webrick up? (I've put the bit leading up to the error below)

Many thanks

Tom

(running ruby 1.8.1 (2003-12-25) [powerpc-darwin])

#2:soks2.rb:516:NameError:>: @wiki.revise( pagename,
upload( "attachment/#{request.query['file'].filename}",
request.query['file'] ) , author, @wiki.content_type( pagename ) )
#2:soks2.rb:516:NameError:<: @wiki.revise( pagename,
upload( "attachment/#{request.query['file'].filename}",
request.query['file'] ) , author, @wiki.content_type( pagename ) )
#2:soks2.rb:516:Exception:>: @wiki.revise( pagename,
upload( "attachment/#{request.query['file'].filename}",
request.query['file'] ) , author, @wiki.content_type( pagename ) )
#2:soks2.rb:516:Exception:<: @wiki.revise( pagename,
upload( "attachment/#{request.query['file'].filename}",
request.query['file'] ) , author, @wiki.content_type( pagename ) )
#2:soks2.rb:516:Exception:>: @wiki.revise( pagename,
upload( "attachment/#{request.query['file'].filename}",
request.query['file'] ) , author, @wiki.content_type( pagename ) )
#2:soks2.rb:516:Exception:<: @wiki.revise( pagename,
upload( "attachment/#{request.query['file'].filename}",
request.query['file'] ) , author, @wiki.content_type( pagename ) )
#2:soks2.rb:516:WikiServlet:: @wiki.revise( pagename,
upload( "attachment/#{request.query['file'].filename}",
request.query['file'] ) , author, @wiki.content_type( pagename ) )
#2:soks2.rb:516:Kernel:<: @wiki.revise( pagename,
upload( "attachment/#{request.query['file'].filename}",
request.query['file'] ) , author, @wiki.content_type( pagename ) )
#2:soks2.rb:488:WikiServlet:<: self.send( verb , request,
response, pagename, request.user)
#2:soks2.rb:488:Kernel:<: self.send( verb , request,
response, pagename, request.user)
#2:/opt/local/lib/ruby/1.8/webrick/httpserver.rb:54:WikiServlet:<:
      service(req, res)
#2:/opt/local/lib/ruby/1.8/webrick/server.rb:150:WEBrick::HTTPServer:<:
          block ? block.call(sock) : run(sock)
#2:/opt/local/lib/ruby/1.8/webrick/httpserver.rb:55:Module:>:
rescue HTTPStatus::EOFError, HTTPStatus::RequestTimeout => ex
#2:/opt/local/lib/ruby/1.8/webrick/httpserver.rb:55:Module:<:
rescue HTTPStatus::EOFError, HTTPStatus::RequestTimeout => ex
#2:/opt/local/lib/ruby/1.8/webrick/httpserver.rb:55:Module:>:
rescue HTTPStatus::EOFError, HTTPStatus::RequestTimeout => ex
#2:/opt/local/lib/ruby/1.8/webrick/httpserver.rb:55:Module:<:
rescue HTTPStatus::EOFError, HTTPStatus::RequestTimeout => ex
#2:/opt/local/lib/ruby/1.8/webrick/httpserver.rb:57:Module:>:
rescue HTTPStatus::Error => ex
#2:/opt/local/lib/ruby/1.8/webrick/httpserver.rb:57:Module:<:
rescue HTTPStatus::Error => ex
#2:/opt/local/lib/ruby/1.8/webrick/httpserver.rb:59:Module:>:
rescue HTTPStatus::Status => ex
#2:/opt/local/lib/ruby/1.8/webrick/httpserver.rb:59:Module:<:
rescue HTTPStatus::Status => ex
#2:/opt/local/lib/ruby/1.8/webrick/httpserver.rb:61:Module:>:
rescue StandardError => ex
#2:/opt/local/lib/ruby/1.8/webrick/httpserver.rb:61:Module:<:
rescue StandardError => ex
#2:/opt/local/lib/ruby/1.8/webrick/httpserver.rb:62:WEBrick::HTTPServer:-:
          @logger.error(ex)
#2:/opt/local/lib/ruby/1.8/webrick/log.rb:49:WEBrick::BasicLog:>:
def error(msg) log(ERROR, "ERROR " << format(msg)); end
#2:/opt/local/lib/ruby/1.8/webrick/log.rb:49:WEBrick::BasicLog:-:
def error(msg) log(ERROR, "ERROR " << format(msg)); end
#2:/opt/local/lib/ruby/1.8/webrick/log.rb:62:WEBrick::BasicLog:>:
def format(arg)
#2:/opt/local/lib/ruby/1.8/webrick/log.rb:63:WEBrick::BasicLog:-:
str = if arg.is_a?(Exception)
#2:/opt/local/lib/ruby/1.8/webrick/log.rb:63:WEBrick::BasicLog:-:
str = if arg.is_a?(Exception)
#2:/opt/local/lib/ruby/1.8/webrick/log.rb:63:Kernel:>: str = if
arg.is_a?(Exception)
#2:/opt/local/lib/ruby/1.8/webrick/log.rb:63:Kernel:<: str = if
arg.is_a?(Exception)
#2:/opt/local/lib/ruby/1.8/webrick/log.rb:65:WEBrick::BasicLog:-:
   arg.backtrace.join("\n\t") << "\n"
#2:/opt/local/lib/ruby/1.8/webrick/log.rb:64:Kernel:>:
"#{arg.class}: #{arg.message}\n\t" <<
#2:/opt/local/lib/ruby/1.8/webrick/log.rb:64:Kernel:<:
"#{arg.class}: #{arg.message}\n\t" <<
#2:/opt/local/lib/ruby/1.8/webrick/log.rb:64:Module:>:
"#{arg.class}: #{arg.message}\n\t" <<
#2:/opt/local/lib/ruby/1.8/webrick/log.rb:64:Module:<:
"#{arg.class}: #{arg.message}\n\t" <<
#2:/opt/local/lib/ruby/1.8/webrick/log.rb:64:Exception:>:
"#{arg.class}: #{arg.message}\n\t" <<
#2:/opt/local/lib/ruby/1.8/webrick/log.rb:64:NameError:>:
"#{arg.class}: #{arg.message}\n\t" <<
#2:/opt/local/lib/ruby/1.8/webrick/log.rb:64:Kernel:>:
"#{arg.class}: #{arg.message}\n\t" <<
#2:/opt/local/lib/ruby/1.8/webrick/log.rb:64:Kernel:>:
"#{arg.class}: #{arg.message}\n\t" <<
#2:/opt/local/lib/ruby/1.8/webrick/log.rb:64:Fixnum:>:
"#{arg.class}: #{arg.message}\n\t" <<
#2:/opt/local/lib/ruby/1.8/webrick/log.rb:64:Fixnum:<:
"#{arg.class}: #{arg.message}\n\t" <<

Thank you Marcus. I'm running ruby 1.8.1 (2003-12-25) that I compiled from source on my Mac (OS X 10.3.5). I have looked at the ruby changelog and can't see mention of this recursion bug, but I have no experience with changelog files, so I may have missed it. I will try installing 1.8.2 over the weekend and see if that fixes it. Thanks, Tom

Markus wrote:

···

I'm not sure at all if this is it, but there was a bug in ruby 1.8
(fixed, I think, in 1.8.1 or 1.8.2) that caused very deep recursion in
some exceptions. Some suggestions:

      * If you can, try it under 1.8.2; I wouldn't recommend blindly
        upgrading as there are some semantics changes between 1.8 and
        1.8.1 that (at least for me) broke things. But it is definitely
        worth testing
      * Search the change logs for the bug. If you compiled ruby from
        source (or can) you may be able to back port the patch.

Let us know what you find out; I'll let you know if I think of anything
further. If you can't try either of the things I've suggested, give a
bit more background information about the environment & I'll take a look
at it this evening.

-- Markus

I'm going on very vague memory here (and Google isn't helpful when
my blood caffeine levels fall too low), but I think the change was:

ruby-1.8.2/ChangeLog

Sat Oct 25 09:18:04 2003 Yukihiro Matsumoto ruby-1.8.2/ChangeLog-
   * eval.c (rb_method_missing): protect exception from within
     "inspect". (ruby-bugs:PR#1204)

and the problem was something to do with missing methods / inspect / and
an exception getting locked in a death spiral recursion. I'd link to
the bug report, but for some reason I'm only finding the Japanese.

-- MarkusQ

···

On Fri, 2004-10-01 at 04:00, Thomas Counsell wrote:

Thank you Marcus. I'm running ruby 1.8.1 (2003-12-25) that I compiled
from source on my Mac (OS X 10.3.5). I have looked at the ruby
changelog and can't see mention of this recursion bug, but I have no
experience with changelog files, so I may have missed it. I will try
installing 1.8.2 over the weekend and see if that fixes it. Thanks, Tom

Markus wrote:
> I'm not sure at all if this is it, but there was a bug in ruby 1.8
> (fixed, I think, in 1.8.1 or 1.8.2) that caused very deep recursion in
> some exceptions. Some suggestions:
>
> * If you can, try it under 1.8.2; I wouldn't recommend blindly
> upgrading as there are some semantics changes between 1.8 and
> 1.8.1 that (at least for me) broke things. But it is definitely
> worth testing
> * Search the change logs for the bug. If you compiled ruby from
> source (or can) you may be able to back port the patch.
>
> Let us know what you find out; I'll let you know if I think of anything
> further. If you can't try either of the things I've suggested, give a
> bit more background information about the environment & I'll take a look
> at it this evening.
>
> -- Markus
>