Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TCP sockets created by java.net.ServerSocket leak to child processes #4234

Open
iaddict opened this issue Oct 19, 2016 · 1 comment
Open

Comments

@iaddict
Copy link
Contributor

iaddict commented Oct 19, 2016

Environment

jruby 9.1.5.0 (2.3.1) 2016-09-07 036ce39 Java HotSpot(TM) 64-Bit Server VM 25.92-b14 on 1.8.0_92-b14 +jit [darwin-x86_64]
OS X 10.10.5 – Darwin Kernel Version 14.5.0

and on

jruby 9.1.5.0 (2.3.1) 2016-09-07 036ce39 Java HotSpot(TM) Server VM 25.102-b14 on 1.8.0_102-b14 +jit [linux-i386]
Linux #1 SMP Fri Dec 11 14:03:26 EST 2015 i686 i686 i386 GNU/Linux

Expected Behavior

Child processes spawned from ruby with Kernel.system should not inherit any open sockets from parent ruby process. This is not true for sockets created with standard java methods like java.net.ServerSocket.

Actual Behavior

Child processes created by Kernel#system (and others like backticks, ..) inherit open sockets from parent process if they are created with standard java methods like java.net.ServerSocket.
This also applies to sockets created by some gems like trinidad or activerecord-jdbc-adapter.

Sockets created with ruby methods like TCPServer.new do not leak.

Example

require 'socket'

# ruby socket, does not leak
serv = TCPServer.new("127.0.0.1", 28561)
Thread.new{ loop { Thread.new { c = serv.accept; c.puts Time.now; c.close; }  }  }

# java socket, does leak
jsocket = Java::java.net.ServerSocket.new(22334)
Thread.new {jsocket.accept}

# show leaked socket in sub process
system('echo $$; lsof -i -a -p $$', close_others: true);
puts `echo $$; lsof -i -a -p $$`

Implications

Long running child processes that hold a handle to socket (and propably are sent to background), can stay alive and hinder another new process to bind to the now already taken port.

Demo

$ jruby -e 'jsocket = Java::java.net.ServerSocket.new(22334); Thread.new {jsocket.accept}; system("sleep 30 &")' # this one starts sleep with socket bound to 22334
$ jruby -e 'jsocket = Java::java.net.ServerSocket.new(22334); Thread.new {jsocket.accept}; system("sleep 30 &")'
Unhandled Java exception: java.net.BindException: Address already in use
java.net.BindException: Address already in use
           socketBind at java/net/PlainSocketImpl.java:-2
                 bind at java/net/AbstractPlainSocketImpl.java:387
                 bind at java/net/ServerSocket.java:375
               <init> at java/net/ServerSocket.java:237
               <init> at java/net/ServerSocket.java:128
          newInstance at java/lang/reflect/Constructor.java:423
    newInstanceDirect at org/jruby/javasupport/JavaConstructor.java:278
          newInstance at org/jruby/RubyClass.java:1001
                 call at org/jruby/RubyClass$INVOKER$i$newInstance.gen:-1
     invokeOther5:new at -e:1
               <main> at -e:1
  invokeWithArguments at java/lang/invoke/MethodHandle.java:627
            runScript at org/jruby/Ruby.java:834
          runNormally at org/jruby/Ruby.java:749
          runNormally at org/jruby/Ruby.java:767
          runFromMain at org/jruby/Ruby.java:580
        doRunFromMain at org/jruby/Main.java:425
          internalRun at org/jruby/Main.java:313
                  run at org/jruby/Main.java:242
                 main at org/jruby/Main.java:204
@iaddict
Copy link
Contributor Author

iaddict commented May 22, 2017

The problem is still present on 9.1.9.0 and in 9.1.10.0.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant