diff options
author | Alan Wu <XrXr@users.noreply.github.com> | 2019-08-19 00:42:29 -0400 |
---|---|---|
committer | Aaron Patterson <tenderlove@github.com> | 2019-08-19 12:44:38 -0700 |
commit | dc0e45e39b37556af8abf6cdb0180e2973041931 (patch) | |
tree | 62f0cd241244b1f80042f1ca328fcf17aca9bbfa | |
parent | 19b0161b851ba32d5bc6c367db5b520d35905d6b (diff) | |
download | ruby-dc0e45e39b37556af8abf6cdb0180e2973041931.tar.gz |
Update moved objects in original_iseq
Without doing this, enabling a TracePoint on a method could lead to use
of moved objects. This was found by running
`env RUBY_ISEQ_DUMP_DEBUG=to_binary make test-all`, which sets
orignal_iseq then runs the compaction tests and the tracepoint tests.
Please excuse the lack of tests. I was not able to figure out how to
reliably trigger a move on a specific iseq imemo to make a good
regression test.
To manually confirm the problem and this fix, you can run:
```
env RUBY_ISEQ_DUMP_DEBUG=to_binary make test-all \
TESTOPTS="test/ruby/test_gc_compact.rb \
test/gdbm/test_gdbm.rb \
test/ruby/test_settracefunc.rb"
```
Or the following script:
```ruby
tp = TracePoint.new(:line) {}
1.times do # put it in a block to not keep these objects alive
objects = 10_000.times.map { Object.new }
objects.hash
end
1.times do
# this allocation pattern can realistically happen in an app
# at load time
beek = 10_000.times.map do
eval(<<-RUBY)
def foo
a + b
1.times {
4 + 234234
}
nil + 234
end
RUBY
Object.new
Object.new
end
beek.hash
end
tp.enable(target: self.:foo) { 234 } # allocate original iseq
GC.verify_compaction_references(toward: :empty)
GC.compact
tp.enable(target: self.:foo) { 234234 } # crash
```
[Bug #16098]
-rw-r--r-- | iseq.c | 8 |
1 files changed, 8 insertions, 0 deletions
@@ -236,6 +236,14 @@ rb_iseq_update_references(rb_iseq_t *iseq) } if (FL_TEST(iseq, ISEQ_MARKABLE_ISEQ)) { rb_iseq_each_value(iseq, update_each_insn_value, NULL); + VALUE *original_iseq = ISEQ_ORIGINAL_ISEQ(iseq); + if (original_iseq) { + size_t n = 0; + const unsigned int size = body->iseq_size; + while (n < size) { + n += iseq_extract_values(original_iseq, n, update_each_insn_value, NULL, rb_vm_insn_null_translator); + } + } } if (body->param.flags.has_kw && ISEQ_COMPILE_DATA(iseq) == NULL) { |