summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog5
-rw-r--r--iseq.c1
-rw-r--r--test/ruby/bug-11928.rb14
-rw-r--r--test/ruby/test_exception.rb6
-rw-r--r--test/ruby/test_iseq.rb27
-rw-r--r--version.h2
6 files changed, 54 insertions, 1 deletions
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 <nobu@ruby-lang.org>
+
+ * 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 <e@80x24.org>
* 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