Issue #9247 has been updated by mrkn (Kenta Murata).

Description updated

I think the following code can reproduce the full cases:

  # https://gist.github.com/mrkn/7945798
  require 'socket'

  # Addrinfo#connect_internal
  puts "(1) Addrinfo#connect (connect_internal)"
  begin
    raise
  rescue
    p Addrinfo.tcp('www.ruby-lang.org', 80).connect
  end

  # Addrinfo.bind
  puts "\n(2) Addrinfo#bind"
  begin
    ai = Addrinfo.tcp(nil, 11229)
    raise
  rescue
    begin
      p ai.bind
    end
  end

  # Addrinfo.listen
  puts "\n(3) Addrinfo#listen"
  begin
    ai = Addrinfo.tcp(nil, 11228)
    raise
  rescue
    begin
      p ai.listen
    end
  end

  # Socket.ip_sockets_port0
  puts "\n(4) Socket.tcp_server_sockets (ip_sockets_port0)"
  begin
    raise
  rescue
    begin
      Socket.tcp_server_sockets(0)
    rescue IOError
      $stderr.puts "#{$!.class}: #{$!}", $!.backtrace
    end
  end

----------------------------------------
Bug #9247: Bugs in socket.rb (exception retrieval)
https://bugs.ruby-lang.org/issues/9247#change-43645

Author: ko1 (Koichi Sasada)
Status: Open
Priority: Normal
Assignee: akr (Akira Tanaka)
Category: lib
Target version: current: 2.1.0
ruby -v: ruby 2.1.0dev (2013-12-13 trunk 44170) [i386-mswin32_110]
Backport: 1.9.3: UNKNOWN, 2.0.0: UNKNOWN


Ruby 2.1 (trunk) 2.0 and 1.9.3 both has a bug to retrieve exception.
In the following code, opened socket is always closed.

require 'socket'
ai = Addrinfo.tcp(nil, 12345)
begin
  raise
rescue
  p ai.listen #=> #<Socket:(closed)>
end

This is because in socket.rb, there are such error handling code:

  # creates a listening socket bound to self.
  def listen(backlog=Socket::SOMAXCONN)
    sock = Socket.new(self.pfamily, self.socktype, self.protocol)
    begin
      sock.ipv6only! if self.ipv6?
      sock.setsockopt(:SOCKET, :REUSEADDR, 1)
      sock.bind(self)
      sock.listen(backlog)
      if block_given?
        yield sock
      else
        sock
      end
    ensure
      ### THIS LINE CLOSE `sock' every time when $! is not nil
      sock.close if !sock.closed? && (block_given? || $!)
    end
  end

There are similar code in socket.rb.

akr-san already knows this issue.
This ticket is to note issues.


We realize this issue because webrick use this feature from 2.1.
The following code no longer works on 2.1.

  begin
    require 'xyzzy' # something like webrick
  rescue LoadError
    require 'webrick' 
    server = WEBrick::HTTPServer.new(Port: 12345)
  end

Because $! is an instance of LoadError.



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