Fixed '#to_io gives NilClass' error
In a race condition in Thrift::NonblockingServer, the following sequence could occur:
1. server transport checked for closure (@server_transport.closed?
returns false)
2. another thread calls server.shutdown
3. yet another thread, scheduled from #shutdown, calls #close on the
server transport, which also sets @handle to nil
4. back in the first thread, #to_io is called on the server transport,
which now returns @handle as nil, causing an error:
1) NonblockingServer Thrift::NonblockingServer should shut down when asked
Failure/Error: rd, = select([@server_transport], nil, nil, 0.1)
TypeError:
can't convert SpecServerSocket to IO (SpecServerSocket#to_io gives NilClass)
# ./lib/thrift/server/nonblocking_server.rb:48:in `select'
# ./lib/thrift/server/nonblocking_server.rb:48:in `block in serve'
# ./lib/thrift/server/nonblocking_server.rb:45:in `loop'
# ./lib/thrift/server/nonblocking_server.rb:45:in `serve'
# ./spec/nonblocking_server_spec.rb:116:in `block (4 levels) in <top (required)>'
This patch changes Thrift::ServerSocket#to_io to raise IOError if
@handle is nil, which is the expected behavior for closed streams in Ruby:
require 'socket'
server = TCPServer.new('localhost', 55554)
server.close
select([server], nil, nil, 0.1)
# => IOError: closed stream
diff --git a/lib/rb/lib/thrift/transport/server_socket.rb b/lib/rb/lib/thrift/transport/server_socket.rb
index 3b85b89..60e4b8a 100644
--- a/lib/rb/lib/thrift/transport/server_socket.rb
+++ b/lib/rb/lib/thrift/transport/server_socket.rb
@@ -59,7 +59,9 @@
@handle.nil? or @handle.closed?
end
- alias to_io handle
+ def to_io
+ @handle || raise(IOError, 'closed stream')
+ end
def to_s
"socket(#{@host}:#{@port})"