jruby / jruby

JRuby, an implementation of Ruby on the JVM
https://www.jruby.org
Other
3.78k stars 921 forks source link

Unnecessary file descriptors not being closed when executing spawn #8234

Open yamam opened 4 months ago

yamam commented 4 months ago

Environment Information

$ ./jruby-9.4.7.0/bin/jruby -v
jruby 9.4.7.0 (3.1.4) 2024-04-29 597ff08ac1 OpenJDK 64-Bit Server VM 21.0.3+9-Ubuntu-1ubuntu1 on 21.0.3+9-Ubuntu-1ubuntu1 +jit [x86_64-linux]
$ uname -a                                                                                                                                                                                [/tmp] 05/13 10:27
Linux PC-DE2307E1253R 5.15.146.1-microsoft-standard-WSL2 #1 SMP Thu Jan 11 04:09:03 UTC 2024 x86_64 x86_64 x86_64 GNU/Linux

Expected Behavior When executing spawn, unnecessary file descriptors should be closed.

Actual Behavior When executing a child process with spawn, unnecessary file descriptors remain open in the child process as shown below:

# ./jruby-9.4.7.0/bin/jruby -e 'system("ls -l /proc/#{spawn(*%w|sleep 1|)}/fd")'
total 0
lrwx------ 1 xxx xxx 64 May 13 10:31 0 -> /dev/pts/12
lrwx------ 1 xxx xxx 64 May 13 10:31 1 -> /dev/pts/12
lrwx------ 1 xxx xxx 64 May 13 10:31 2 -> /dev/pts/12
lrwx------ 1 xxx xxx 64 May 13 10:31 3 -> 'socket:[22456786]'
lr-x------ 1 xxx xxx 64 May 13 10:31 4 -> /usr/lib/jvm/java-21-openjdk-amd64/lib/modules
lr-x------ 1 xxx xxx 64 May 13 10:31 5 -> /tmp/jruby-9.4.7.0/lib/jruby.jar
lr-x------ 1 xxx xxx 64 May 13 10:31 6 -> /dev/urandom
lr-x------ 1 xxx xxx 64 May 13 10:31 7 -> /dev/random
yamam commented 4 months ago

The Open3.popen3 method uses spawn internally, so unnecessary file descriptors are not closed in the same way.

$ ./jruby-9.4.7.0/bin/jruby -e 'require "open3";_, _, _, th = Open3.popen3("sleep", "1"); system("ls -l /proc/#{th[:pid]}/fd")'
total 0
lr-x------ 1 xxx xxx 64 May 13 11:06 0 -> 'pipe:[22615552]'
l-wx------ 1 xxx xxx 64 May 13 11:06 1 -> 'pipe:[22615553]'
l-wx------ 1 xxx xxx 64 May 13 11:06 2 -> 'pipe:[22615554]'
lrwx------ 1 xxx xxx 64 May 13 11:06 3 -> 'socket:[22456786]'
lr-x------ 1 xxx xxx 64 May 13 11:06 4 -> /usr/lib/jvm/java-21-openjdk-amd64/lib/modules
lr-x------ 1 xxx xxx 64 May 13 11:06 5 -> /tmp/jruby-9.4.7.0/lib/jruby.jar
lr-x------ 1 xxx xxx 64 May 13 11:06 6 -> /dev/urandom
lr-x------ 1 xxx xxx 64 May 13 11:06 7 -> /dev/random

On the other hand, when using IO.popen3, unnecessary file descriptors are closed as follows:

$ ./jruby-9.4.7.0/bin/jruby -e 'IO.popen3("sleep", "1"); system("ls -l /proc/#{`pgrep sleep`.chomp}/fd")'
total 0
lr-x------ 1 xxx xxx 64 May 13 11:04 0 -> 'pipe:[22621486]'
l-wx------ 1 xxx xxx 64 May 13 11:04 1 -> 'pipe:[22621487]'
l-wx------ 1 xxx xxx 64 May 13 11:04 2 -> 'pipe:[22621488]'

By the way, it seems that the :pid of the fourth return value of IO.popen3 is incorrect:

$ ./jruby-9.4.7.0/bin/jruby -e '_, _, _, th = IO.popen3("sleep", "1"); system("ls -l /proc/#{th[:pid]}/fd")'
ls: cannot access '/proc/1414042262/fd': No such file or directory