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

ruby-changes:39358

From: nobu <ko1@a...>
Date: Thu, 30 Jul 2015 10:42:48 +0900 (JST)
Subject: [ruby-changes:39358] nobu:r51439 (trunk): load.c: avoid segfault when 'throw' occurs in the middle of rb_load_file_str

nobu	2015-07-30 10:42:35 +0900 (Thu, 30 Jul 2015)

  New Revision: 51439

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

  Log:
    load.c: avoid segfault when 'throw' occurs in the middle of rb_load_file_str
    
    How can a 'throw' happen while the current thread is reading a Ruby source file
    from disk and parsing it? It can happen if another thread calls Thread#raise,
    and passes an Exception object which responds to #exception, and the custom #exception
    method calls Kernel#throw.
    
    In practice, this is most likely to happen if you combine the use of autoload and
    Timeout.timeout.
    
    An extra check is required to avoid a segfault in this case.
    
    * load.c (rb_load_internal0): extra check before returning TAG_RAISE when a
      non-local transfer of control happens while loading and parsing a Ruby source file.
      [ruby-core:70169] [Bug #11404]

  Modified files:
    trunk/ChangeLog
    trunk/load.c
    trunk/test/ruby/test_require.rb
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 51438)
+++ ChangeLog	(revision 51439)
@@ -1,3 +1,10 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1
+Thu Jul 30 10:42:27 2015  Alex Dowad  <alexinbeijing@g...>
+
+	* load.c (rb_load_internal0): extra check before returning
+	  TAG_RAISE when a non-local transfer of control happens while
+	  loading and parsing a Ruby source file.
+	  [ruby-core:70169] [Bug #11404]
+
 Thu Jul 30 08:48:42 2015  Eric Wong  <e@8...>
 
 	* st.c (find_entry): constify st_table*
Index: load.c
===================================================================
--- load.c	(revision 51438)
+++ load.c	(revision 51439)
@@ -621,7 +621,7 @@ rb_load_internal0(rb_thread_t *th, VALUE https://github.com/ruby/ruby/blob/trunk/load.c#L621
     th->top_self = self;
     th->top_wrapper = wrapper;
 
-    if (!loaded && !FIXNUM_P(th->errinfo)) {
+    if (!loaded && !FIXNUM_P(th->errinfo) && state != TAG_THROW) {
 	/* an error on loading don't include INT2FIX(TAG_FATAL) see r35625 */
 	return TAG_RAISE;
     }
Index: test/ruby/test_require.rb
===================================================================
--- test/ruby/test_require.rb	(revision 51438)
+++ test/ruby/test_require.rb	(revision 51439)
@@ -706,4 +706,33 @@ class TestRequire < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_require.rb#L706
       END
     }
   end unless /mswin|mingw/ =~ RUBY_PLATFORM
+
+  def test_throw_while_loading
+    Tempfile.create(%w'bug-11404 .rb') do |f|
+      f.puts 'sleep'
+      f.close
+
+      assert_separately(["-", f.path], <<-'end;')
+        path = ARGV[0]
+        class Error < RuntimeError
+          def exception(*)
+            begin
+              throw :blah
+            rescue UncaughtThrowError
+            end
+            self
+          end
+        end
+
+        assert_throw(:blah) do
+          x = Thread.current
+          y = Thread.start {
+            sleep 0.00001
+            x.raise Error.new
+          }
+          load path
+        end
+      end;
+    end
+  end
 end

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

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