[前][次][番号順一覧][スレッド一覧]

ruby-changes:44315

From: nobu <ko1@a...>
Date: Mon, 10 Oct 2016 15:22:34 +0900 (JST)
Subject: [ruby-changes:44315] nobu:r56388 (trunk): ruby.c: bind fd before waiting

nobu	2016-10-10 15:22:30 +0900 (Mon, 10 Oct 2016)

  New Revision: 56388

  https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=56388

  Log:
    ruby.c: bind fd before waiting
    
    * ruby.c (open_load_file): bind the open fd to an IO instance
      before waiting FIFO, not to leak the fd if interrupted.

  Modified files:
    trunk/ChangeLog
    trunk/ruby.c
    trunk/test/ruby/test_require.rb
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 56387)
+++ ChangeLog	(revision 56388)
@@ -1,3 +1,8 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1
+Mon Oct 10 15:22:27 2016  Nobuyoshi Nakada  <nobu@r...>
+
+	* ruby.c (open_load_file): bind the open fd to an IO instance
+	  before waiting FIFO, not to leak the fd if interrupted.
+
 Mon Oct 10 12:40:54 2016  Nobuyoshi Nakada  <nobu@r...>
 
 	* ruby.c (open_load_file): compare with EXEEXT instead of hard
Index: test/ruby/test_require.rb
===================================================================
--- test/ruby/test_require.rb	(revision 56387)
+++ test/ruby/test_require.rb	(revision 56388)
@@ -757,6 +757,26 @@ class TestRequire < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_require.rb#L757
     }
   end if File.respond_to?(:mkfifo)
 
+  def test_loading_fifo_fd_leak
+    Tempfile.create(%w'fifo .rb') {|f|
+      f.close
+      File.unlink(f.path)
+      File.mkfifo(f.path)
+      assert_separately(["-", f.path], "#{<<-"begin;"}\n#{<<-"end;"}", timeout: 3)
+      begin;
+        Process.setrlimit(Process::RLIMIT_NOFILE, 50)
+        th = Thread.current
+        100.times do |i|
+          Thread.start {begin sleep(0.001) end until th.stop?; th.raise(IOError)}
+          assert_raise(IOError, "\#{i} time") do
+            tap {tap {tap {load(ARGV[0])}}}
+          end
+          GC.start
+        end
+      end;
+    }
+  end if File.respond_to?(:mkfifo) and defined?(Process::RLIMIT_NOFILE)
+
   def test_throw_while_loading
     Tempfile.create(%w'bug-11404 .rb') do |f|
       f.puts 'sleep'
Index: ruby.c
===================================================================
--- ruby.c	(revision 56387)
+++ ruby.c	(revision 56388)
@@ -1916,22 +1916,20 @@ open_load_file(VALUE fname_v, int *xflag https://github.com/ruby/ruby/blob/trunk/ruby.c#L1916
 #endif
 
 	e = ruby_is_fd_loadable(fd);
-	if (e <= 0) {
-	    if (!e) {
-		e = errno;
-		(void)close(fd);
-		rb_load_fail(fname_v, strerror(e));
-	    }
-	    else {
-		/*
-		  We need to wait if FIFO is empty. It's FIFO's semantics.
-		  rb_thread_wait_fd() release GVL. So, it's safe.
-		*/
-		rb_thread_wait_fd(fd);
-	    }
+	if (!e) {
+	    e = errno;
+	    (void)close(fd);
+	    rb_load_fail(fname_v, strerror(e));
 	}
 
 	f = rb_io_fdopen(fd, mode, fname);
+	if (e < 0) {
+	    /*
+	      We need to wait if FIFO is empty. It's FIFO's semantics.
+	      rb_thread_wait_fd() release GVL. So, it's safe.
+	    */
+	    rb_thread_wait_fd(fd);
+	}
     }
     return f;
 }

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]