mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
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] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@51439 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
d0240cbb6d
commit
bcba951320
3 changed files with 37 additions and 1 deletions
|
@ -1,3 +1,10 @@
|
|||
Thu Jul 30 10:42:27 2015 Alex Dowad <alexinbeijing@gmail.com>
|
||||
|
||||
* 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@80x24.org>
|
||||
|
||||
* st.c (find_entry): constify st_table*
|
||||
|
|
2
load.c
2
load.c
|
@ -621,7 +621,7 @@ rb_load_internal0(rb_thread_t *th, VALUE fname, int wrap)
|
|||
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;
|
||||
}
|
||||
|
|
|
@ -706,4 +706,33 @@ class TestRequire < Test::Unit::TestCase
|
|||
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
|
||||
|
|
Loading…
Reference in a new issue