Project

General

Profile

Bug #13239

Bug with "special exceptions" when they are thrown in context of a rescue clause.

Added by nvashchenko (Nikolay Vashchenko) over 2 years ago. Updated over 1 year ago.

Status:
Closed
Priority:
Normal
Assignee:
-
Target version:
-
ruby -v:
2.4.x, 2.3.x, etc
[ruby-core:79641]

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

Associated revisions

Revision 57415
Added by nobu (Nobuyoshi Nakada) over 2 years ago

eval.c: copy special exception

  • eval.c (setup_exception): make unfrozen copy of special exception before setting up a cause.

Revision 57474
Added by nobu (Nobuyoshi Nakada) over 2 years ago

test_io.rb: separate a test

  • test/ruby/test_io.rb (test_closed_stream_in_rescue): run in a separated process.

Revision 2132fb9f
Added by usa (Usaku NAKAMURA) almost 2 years ago

merge revision(s) 57415,57474: [Backport #13239]

    eval.c: copy special exception

    * eval.c (setup_exception): make unfrozen copy of special
      exception before setting up a cause.
    test_io.rb: separate a test

    * test/ruby/test_io.rb (test_closed_stream_in_rescue): run in a
      separated process.

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_2_3@59538 b2dd03c8-39d4-4d8f-98ff-823fe69b080e

Revision 59538
Added by usa (Usaku NAKAMURA) almost 2 years ago

merge revision(s) 57415,57474: [Backport #13239]

eval.c: copy special exception

* eval.c (setup_exception): make unfrozen copy of special
  exception before setting up a cause.
test_io.rb: separate a test

* test/ruby/test_io.rb (test_closed_stream_in_rescue): run in a
  separated process.

History

Updated by nobu (Nobuyoshi Nakada) over 2 years ago

  • Status changed from Open to Feedback
  • Description updated (diff)

It has been fixed at r57415, I think.

Updated by nvashchenko (Nikolay Vashchenko) over 2 years ago

Yes, that appears to be the case, thanks you.

Updated by matthewd (Matthew Draper) over 2 years ago

Should this be closed for backporting?

Updated by shyouhei (Shyouhei Urabe) over 2 years ago

  • Backport changed from 2.2: UNKNOWN, 2.3: UNKNOWN, 2.4: UNKNOWN to 2.2: UNKNOWN, 2.3: REQUIRED, 2.4: REQUIRED
  • Status changed from Feedback to Closed

matthewd (Matthew Draper) wrote:

Should this be closed for backporting?

OK, closing.

Updated by nagachika (Tomoyuki Chikanaga) about 2 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) almost 2 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 1 year 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

Also available in: Atom PDF