Exception never raised when threading an eval containing a malformed command [might be a bug ?]

B

Benjamin Babut

Hello everyone!

I've encountered a strange issue when coding a tool extending ruby, and =
=

was wondering if I was missing something... I'm working under windows wi=
th =

the last stable release of ruby (1.8.5-21) and did not find a way to deb=
ug =

ruby sources to observe the behaviour. This is reproductible with just t=
he =

common ruby interpreter. Let me explain the problem :

First let's consider this small script :

#!/usr/bin/env ruby
$FOO+2

We get the evident result ($FOO is not defined, an exception's raised) :=


test.rb:2: undefined method `+' for nil:NilClass (NoMethodError)

Then let's consider this small script :

#!/usr/bin/env ruby
eval("puts \"foo")

You can see that the string given to puts is malformed, so we get again =
an =

exception :

(eval):1: compile error (SyntaxError)
(eval):1: unterminated string meets end of file

Ok. Now let's thread this. Let's consider the following script :

#!/usr/bin/env ruby
def newthread()
toret =3D Thread.new {
puts "START"
begin
$FOO+2
rescue
puts("EXCEPTION !!!!!!!!")
end
puts "END"
}
return toret
end

$TESTTHREAD =3D newthread()
2.times {
if(!$TESTTHREAD.alive?) then
puts "DEAD, RESURRECTING"
$TESTTHREAD =3D newthread()
sleep(4)
end
}

We create a thread, provoke an exception, catch it, restart the thread, =
=

and so on twice again. We get the following expected behaviour :

START
EXCEPTION !!!!!!!!
END
DEAD, RESURRECTING
START
EXCEPTION !!!!!!!!
END
DEAD, RESURRECTING
START
EXCEPTION !!!!!!!!
END

But now, let's consider this (here comes the issue) : we do exactly the =
=

same thing (we only replace the $FOO+2 line by our malformed eval-puts) =
:

#!/usr/bin/env ruby
def newthread()
toret =3D Thread.new {
puts "START"
begin
eval("puts \"foo")
rescue
puts("EXCEPTION !!!!!!!!")
end
puts "END"
}
return toret
end

$TESTTHREAD =3D newthread()
2.times {
if(!$TESTTHREAD.alive?) then
puts "DEAD, RESURRECTING"
$TESTTHREAD =3D newthread()
sleep(4)
end
}

And then we get...

START
DEAD, RESURRECTING
START
DEAD, RESURRECTING
START

(!!) It simply seems that the ruby thread dies inside the eval, and the =
=

exception is never raised (?). Has someone an explanation for this ? =

(found a bug somewhere ?) :)

Many thanks by advance for those who'd work on that matter!

Ben
 
J

Jan Svitok

Hello everyone!

I've encountered a strange issue when coding a tool extending ruby, and
was wondering if I was missing something... I'm working under windows with
the last stable release of ruby (1.8.5-21) and did not find a way to debug
ruby sources to observe the behaviour. This is reproductible with just the
common ruby interpreter. Let me explain the problem :

First let's consider this small script :

#!/usr/bin/env ruby
$FOO+2

We get the evident result ($FOO is not defined, an exception's raised) :

test.rb:2: undefined method `+' for nil:NilClass (NoMethodError)

Then let's consider this small script :

#!/usr/bin/env ruby
eval("puts \"foo")

You can see that the string given to puts is malformed, so we get again an
exception :

(eval):1: compile error (SyntaxError)
(eval):1: unterminated string meets end of file

Ok. Now let's thread this. Let's consider the following script :

#!/usr/bin/env ruby
def newthread()
toret = Thread.new {
puts "START"
begin
$FOO+2
rescue
puts("EXCEPTION !!!!!!!!")
end
puts "END"
}
return toret
end

$TESTTHREAD = newthread()
2.times {
if(!$TESTTHREAD.alive?) then
puts "DEAD, RESURRECTING"
$TESTTHREAD = newthread()
sleep(4)
end
}

We create a thread, provoke an exception, catch it, restart the thread,
and so on twice again. We get the following expected behaviour :

START
EXCEPTION !!!!!!!!
END
DEAD, RESURRECTING
START
EXCEPTION !!!!!!!!
END
DEAD, RESURRECTING
START
EXCEPTION !!!!!!!!
END

But now, let's consider this (here comes the issue) : we do exactly the
same thing (we only replace the $FOO+2 line by our malformed eval-puts) :

#!/usr/bin/env ruby
def newthread()
toret = Thread.new {
puts "START"
begin
eval("puts \"foo")
rescue
puts("EXCEPTION !!!!!!!!")
end
puts "END"
}
return toret
end

$TESTTHREAD = newthread()
2.times {
if(!$TESTTHREAD.alive?) then
puts "DEAD, RESURRECTING"
$TESTTHREAD = newthread()
sleep(4)
end
}

And then we get...

START
DEAD, RESURRECTING
START
DEAD, RESURRECTING
START

(!!) It simply seems that the ruby thread dies inside the eval, and the
exception is never raised (?). Has someone an explanation for this ?
(found a bug somewhere ?) :)

Many thanks by advance for those who'd work on that matter!

Hi,

it's easy:
$FOO+2 raises NoMethodError < StandardError
while eval(..) raises SyntaxError !< StandardError

empty rescue == rescue StandardError

If you want to catch ALL exceptions, use rescue Exception.

For exceptions hierarchy see
http://www.zenspider.com/Languages/Ruby/QuickRef.html#34
 
E

Ezra Zygmuntowicz

Hi~

Hello everyone!

I've encountered a strange issue when coding a tool extending ruby,
and was wondering if I was missing something... I'm working under
windows with the last stable release of ruby (1.8.5-21) and did not
find a way to debug ruby sources to observe the behaviour. This is
reproductible with just the common ruby interpreter. Let me explain
the problem :

First let's consider this small script :

#!/usr/bin/env ruby
$FOO+2

We get the evident result ($FOO is not defined, an exception's
raised) :

test.rb:2: undefined method `+' for nil:NilClass (NoMethodError)

Then let's consider this small script :

#!/usr/bin/env ruby
eval("puts \"foo")

You can see that the string given to puts is malformed, so we get
again an exception :

(eval):1: compile error (SyntaxError)
(eval):1: unterminated string meets end of file

Ok. Now let's thread this. Let's consider the following script :

#!/usr/bin/env ruby
def newthread()
toret = Thread.new {
puts "START"
begin
$FOO+2
rescue
puts("EXCEPTION !!!!!!!!")
end
puts "END"
}
return toret
end

$TESTTHREAD = newthread()
2.times {
if(!$TESTTHREAD.alive?) then
puts "DEAD, RESURRECTING"
$TESTTHREAD = newthread()
sleep(4)
end
}

We create a thread, provoke an exception, catch it, restart the
thread, and so on twice again. We get the following expected
behaviour :

START
EXCEPTION !!!!!!!!
END
DEAD, RESURRECTING
START
EXCEPTION !!!!!!!!
END
DEAD, RESURRECTING
START
EXCEPTION !!!!!!!!
END

But now, let's consider this (here comes the issue) : we do exactly
the same thing (we only replace the $FOO+2 line by our malformed
eval-puts) :

#!/usr/bin/env ruby
def newthread()
toret = Thread.new {
puts "START"
begin
eval("puts \"foo")
rescue
puts("EXCEPTION !!!!!!!!")
end
puts "END"
}
return toret
end

$TESTTHREAD = newthread()
2.times {
if(!$TESTTHREAD.alive?) then
puts "DEAD, RESURRECTING"
$TESTTHREAD = newthread()
sleep(4)
end
}

And then we get...

START
DEAD, RESURRECTING
START
DEAD, RESURRECTING
START

(!!) It simply seems that the ruby thread dies inside the eval, and
the exception is never raised (?). Has someone an explanation for
this ? (found a bug somewhere ?) :)

Many thanks by advance for those who'd work on that matter!

Ben

Ben-

By default ruby doesn't propogate exceptions up out of the threads,
if an exception is raised in a thread that thread will just silently
dies. To make exceptions in a thread raise to the top level you need
to set this in your script:

Thread.abort_on_exception = true


Cheers-

-- Ezra Zygmuntowicz
-- Lead Rails Evangelist
-- (e-mail address removed)
-- Engine Yard, Serious Rails Hosting
-- (866) 518-YARD (9273)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,982
Messages
2,570,186
Members
46,740
Latest member
JudsonFrie

Latest Threads

Top