Project

General

Profile

Bug #19041 ยป manifest_weakref_issue.rb

Script to reproduce the issue - parker (Parker Finch), 02/03/2023 02:49 PM

 
#!/usr/bin/env ruby

# This version does manifest the issue. (It gets stuck in the inner loop and
# never terminates.)
require "weakref"
require "objspace"
require "json"

puts "Ruby version: #{RUBY_VERSION}"

iterations = 0

def address(object)
JSON.parse(ObjectSpace.dump(object, output: :string)).fetch("address")
end

while iterations < 2
puts "Iteration: #{iterations}"
object_address = nil

obj = WeakRef.new(Object.new.tap { |o| object_address = address(o) })
puts "Object address: #{object_address}"

inner_iterations = 0

while obj.weakref_alive?
# Sleep to give registers a chance to clear.
sleep(0.5)

# Call the `WeakRef#weakref_alive?` method to see if that causes the issue
# to manifest. (It does, GC does _not_ clear out the underlying Object after
# this.)
obj.weakref_alive?

# If we make it through multiple inner iterations, then this issue is
# manifesting. This is the case where we want to see what is holding a
# reference to the underlying object. Interestingly, it seems like the
# `exit` here isn't even necessary -- the `puts` (or the ObjectSpace dump
# inside it) is enough to prevent the issue from manifesting. But leaving
# the `exit` for clarity.
if inner_iterations == 3
puts(
ObjectSpace.dump_all(output: :string).each_line.select do |line|
line.include?(object_address)
end
)
exit(1)
end

GC.start
inner_iterations += 1
puts "Inner iterations: #{inner_iterations}"
end
iterations += 1
end
    (1-1/1)