From d3c05ae77c933257f874fe043b4e370a935c1ec3 Mon Sep 17 00:00:00 2001 From: naruse Date: Tue, 29 Mar 2016 14:15:17 +0000 Subject: merge revision(s) 53514,53524: [Backport #11928] * iseq.c (iseqw_mark): as wrapped iseq is isolated from the call stack, it needs to take care of its parent and ancestors, so that they do not become orphans. [ruby-core:72620] [Bug #11928] * iseq.c (rb_iseq_mark): mark parent iseq to prevent dynamically generated iseq by eval from GC. [ruby-core:72620] [Bug #11928] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_2_3@54405 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 5 +++++ iseq.c | 1 + test/ruby/bug-11928.rb | 14 ++++++++++++++ test/ruby/test_exception.rb | 6 ++++++ test/ruby/test_iseq.rb | 27 +++++++++++++++++++++++++++ version.h | 2 +- 6 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 test/ruby/bug-11928.rb diff --git a/ChangeLog b/ChangeLog index 387a3b2f1c..b2a0507250 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +Tue Mar 29 23:10:47 2016 Nobuyoshi Nakada + + * iseq.c (rb_iseq_mark): mark parent iseq to prevent dynamically + generated iseq by eval from GC. [ruby-core:72620] [Bug #11928] + Tue Mar 29 22:56:44 2016 Eric Wong * lib/resolv.rb (Resolv::IPv6.create): avoid modifying frozen diff --git a/iseq.c b/iseq.c index 3c68264262..e679108558 100644 --- a/iseq.c +++ b/iseq.c @@ -113,6 +113,7 @@ rb_iseq_mark(const rb_iseq_t *iseq) rb_gc_mark(body->location.base_label); rb_gc_mark(body->location.path); RUBY_MARK_UNLESS_NULL(body->location.absolute_path); + RUBY_MARK_UNLESS_NULL((VALUE)body->parent_iseq); } if (FL_TEST(iseq, ISEQ_NOT_LOADED_YET)) { diff --git a/test/ruby/bug-11928.rb b/test/ruby/bug-11928.rb new file mode 100644 index 0000000000..72b3b0f8ed --- /dev/null +++ b/test/ruby/bug-11928.rb @@ -0,0 +1,14 @@ +class Segfault + at_exit { Segfault.new.segfault } + + define_method 'segfault' do + n = 11928 + v = nil + i = 0 + while i < n + i += 1 + v = (foo rescue $!).local_variables + end + assert_equal(%i[i n v], v.sort) + end +end diff --git a/test/ruby/test_exception.rb b/test/ruby/test_exception.rb index 1148277a1b..91732dd062 100644 --- a/test/ruby/test_exception.rb +++ b/test/ruby/test_exception.rb @@ -701,6 +701,12 @@ end.join assert_equal(%i[a b c d e f g], e.local_variables.sort) end + def test_name_error_info_parent_iseq_mark + assert_separately(['-', File.join(__dir__, 'bug-11928.rb')], <<-'end;') + -> {require ARGV[0]}.call + end; + end + def test_output_string_encoding # "\x82\xa0" in cp932 is "\u3042" (Japanese hiragana 'a') # change $stderr to force calling rb_io_write() instead of fwrite() diff --git a/test/ruby/test_iseq.rb b/test/ruby/test_iseq.rb index 4f7616a0db..7af8c1b11b 100644 --- a/test/ruby/test_iseq.rb +++ b/test/ruby/test_iseq.rb @@ -185,4 +185,31 @@ class TestISeq < Test::Unit::TestCase labels = body.select {|op, arg| op == :branchnil}.map {|op, arg| arg} assert_equal(1, labels.uniq.size) end + + def test_parent_iseq_mark + assert_separately([], <<-'end;') + ->{ + ->{ + ->{ + eval <<-EOS + class Segfault + define_method :segfault do + x = nil + GC.disable + 1000.times do |n| + n.times do + x = (foo rescue $!).local_variables + end + GC.start + end + x + end + end + EOS + }.call + }.call + }.call + at_exit { assert_equal([:n, :x], Segfault.new.segfault.sort) } + end; + end end diff --git a/version.h b/version.h index 91980039f4..695edf65cb 100644 --- a/version.h +++ b/version.h @@ -1,6 +1,6 @@ #define RUBY_VERSION "2.3.0" #define RUBY_RELEASE_DATE "2016-03-29" -#define RUBY_PATCHLEVEL 53 +#define RUBY_PATCHLEVEL 54 #define RUBY_RELEASE_YEAR 2016 #define RUBY_RELEASE_MONTH 3 -- cgit v1.2.3