Bug #13239
closedBug with "special exceptions" when they are thrown in context of a rescue clause.
Description
I've stumbled upon a case when ruby is supposed to throw "IOError: stream closed"(https://github.com/ruby/ruby/blob/trunk/thread.c#L4823) because there was a retained FD lock by another thread, but I'm was getting this instead of it:
RuntimeError: can't modify frozen IOError
/home/vagrant/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/puma-3.6.2/lib/puma/server.rb:877:in `write'
/home/vagrant/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/puma-3.6.2/lib/puma/server.rb:877:in `<<'
/home/vagrant/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/puma-3.6.2/lib/puma/server.rb:877:in `stop'
I've done some digging and it appeared to a be a ruby bug with how such exceptions(so called "special exceptions") are handled. This exception is being frozen right after creation: https://github.com/ruby/ruby/blob/trunk/vm.c#L2078 but later, when it's thrown, it's being handled exactly as regular exception that is not frozen, which leads to a problem here:
https://github.com/ruby/ruby/blob/trunk/eval.c#L511 - it is an attempt to assign the "#cause" attribute on it when it all happens inside a rescue clause, since the exception itself is frozen.
I've created a script to reproduce it:
rd, wr = IO.pipe
Thread.new do
IO.select [rd]
wr.close
end
begin
raise 'any exception'
rescue
wr << 'A'
end
It works with this ruby fork where I've added sleep for couple of seconds to imitate slow system call response, to keep the FD locked for a while and produce initial exception: https://github.com/ruby/ruby/blob/trunk/eval.c#L511
Updated by nvashchenko (Nikolay Vashchenko) over 7 years ago
Oops, wrong link to the ruby fork.
Here's the right one: https://github.com/NickolasVashchenko/ruby/commits/special_exc_cause_bug
Updated by nobu (Nobuyoshi Nakada) over 7 years ago
- Description updated (diff)
- Status changed from Open to Feedback
It has been fixed at r57415, I think.
Updated by nvashchenko (Nikolay Vashchenko) over 7 years ago
Yes, that appears to be the case, thanks you.
Updated by matthewd (Matthew Draper) over 7 years ago
Should this be closed for backporting?
Updated by shyouhei (Shyouhei Urabe) over 7 years ago
- Status changed from Feedback to Closed
- Backport changed from 2.2: UNKNOWN, 2.3: UNKNOWN, 2.4: UNKNOWN to 2.2: UNKNOWN, 2.3: REQUIRED, 2.4: REQUIRED
matthewd (Matthew Draper) wrote:
Should this be closed for backporting?
OK, closing.
Updated by nagachika (Tomoyuki Chikanaga) over 7 years ago
- Backport changed from 2.2: UNKNOWN, 2.3: REQUIRED, 2.4: REQUIRED to 2.2: UNKNOWN, 2.3: REQUIRED, 2.4: DONE
Backported into ruby_2_4 at r57939.
Updated by usa (Usaku NAKAMURA) about 7 years ago
- Backport changed from 2.2: UNKNOWN, 2.3: REQUIRED, 2.4: DONE to 2.2: UNKNOWN, 2.3: DONE, 2.4: DONE
ruby_2_3 r59538 merged revision(s) 57415,57474.
Updated by MSP-Greg (Greg L) over 6 years ago
Obviously, 2.2 changes are soon to be stopped.
Recently in Puma, Travis was changed from 2.2.8 to 2.2.9, and in code using a pipe, the "can't modify frozen IOError" occurred.
This was not an issue with 2.2.8, which was used in Puma / Travis testing since 2017-09-18.
So, the question is, might this be backported to 2.2?
Thanks, Greg