mirror of
https://github.com/ruby/ruby.git
synced 2026-10-28 16:36:20 +08:00
class_allocate_complex_instance() allocates the object with an extended
shape and fills in as.extended only after allocating the fields object.
A GC during that allocation sees a shape that says "extended" and marks
whatever the reused slot left in as.extended:
[BUG] try to mark T_NONE object (obj: out-of-heap:..., parent: ... T_OBJECT/(complex) ...)
Before 86951165b8 ("Get rid of ROBJECT_HEAP flag") the mark path keyed
off the ROBJECT_HEAP flag, which was set together with as.extended, so
the window took the embedded path and read nothing. The shape is now
set at allocation, which makes the window live.
Reproduces with GC.stress on a class whose instances start with a
complex shape, e.g. bootstraptest/test_yjit.rb under `-s`. Add a
bootstraptest that enables GC.stress itself so a regular btest run
covers it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
46 lines
1.1 KiB
Ruby
46 lines
1.1 KiB
Ruby
assert_normal_exit %q{
|
|
a = []
|
|
ms = "a".."k"
|
|
("A".."Z").each do |mod|
|
|
mod = eval("module #{mod}; self; end")
|
|
ms.each do |meth|
|
|
iseq = RubyVM::InstructionSequence.compile("module #{mod}; def #{meth}; end; end")
|
|
GC.stress = true
|
|
iseq.eval
|
|
GC.stress = false
|
|
end
|
|
o = Object.new.extend(mod)
|
|
ms.each do |meth|
|
|
o.send(meth)
|
|
end
|
|
end
|
|
}, '[ruby-dev:39453]'
|
|
|
|
assert_normal_exit %q{
|
|
a = []
|
|
ms = "a".."k"
|
|
("A".."Z").each do |mod|
|
|
mod = eval("module #{mod}; self; end")
|
|
ms.each do |meth|
|
|
GC.stress = true
|
|
mod.module_eval {define_method(meth) {}}
|
|
GC.stress = false
|
|
end
|
|
o = Object.new.extend(mod)
|
|
ms.each do |meth|
|
|
o.send(meth)
|
|
end
|
|
end
|
|
}, '[ruby-dev:39453]'
|
|
|
|
assert_normal_exit %q{
|
|
# A class whose instances start with a complex shape: as.extended must be
|
|
# initialized before the fields object allocation can trigger a GC.
|
|
ivars = 1024.times.map { |i| "@iv_#{i} = #{i}\n" }.join
|
|
klass = Class.new
|
|
klass.class_eval "def initialize() #{ivars} end"
|
|
GC.stress = true
|
|
klass.allocate
|
|
GC.stress = false
|
|
}, 'complex T_OBJECT marked before as.extended is set'
|