From: shyouhei@...
Date: 2017-04-06T03:27:26+00:00
Subject: [ruby-core:80590] [Ruby trunk Bug#13239][Closed] Bug with "special exceptions" when they are thrown in context of a rescue clause.

Issue #13239 has been updated by shyouhei (Shyouhei Urabe).

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.


----------------------------------------
Bug #13239: Bug with "special exceptions" when they are thrown in context of a rescue clause.
https://bugs.ruby-lang.org/issues/13239#change-64093

* Author: nvashchenko (Nikolay Vashchenko)
* Status: Closed
* Priority: Normal
* Assignee: 
* Target version: 
* ruby -v: 2.4.x, 2.3.x, etc
* Backport: 2.2: UNKNOWN, 2.3: REQUIRED, 2.4: REQUIRED
----------------------------------------
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: 

```ruby
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



-- 
https://bugs.ruby-lang.org/

Unsubscribe: <mailto:ruby-core-request@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>