💬

[Bug #20253] ObjectSpace.define_finalizer に Proc#dup を渡したときのバグ報告

2024/04/13に公開

[Bug #20253] Proc.dup and Proc#clone don't preserve finalizers

  • ObjectSpace.define_finalizer に渡したオブジェクトを #dup/clone した場合はその複製したオブジェクトごとに finalizer が呼ばれる
def fin(sym)
  # obj が解放されるときにこのブロックが呼ばれる
  ->(obj) { p "#{sym}: #{obj}" }
end

obj = Object.new
ObjectSpace.define_finalizer(obj, fin(:obj))
obj.dup
obj.clone
__END__
output:
"obj: 60"
"obj: 80"
"obj: 100"
  • これが objProc の場合は呼ばれないというバグ報告
def fin(sym)
  # obj が解放されるときにこのブロックが呼ばれる
  ->(obj) { p "#{sym}: #{obj}" }
end

proc = Proc.new { }
ObjectSpace.define_finalizer(proc, fin(:proc))
# ここでコピーしたオブジェクトの finalizer は呼ばれない
proc.dup
proc.clone
__END__
"proc: 60"
  • 他にも Proc#dup した場合はインスタンス変数がコピーされない、みたいな挙動もあるみたいですね
def ivar_dup(obj)
  obj.instance_variable_set(:@foo, 1)
  p [:dup, obj.dup.instance_variable_get(:@foo)]
  p [:clone, obj.clone.instance_variable_get(:@foo)]
end

ivar_dup(Object.new)
ivar_dup(Proc.new { })
__END__
output:
[:dup, 1]
[:clone, 1]
[:dup, nil]
[:clone, 1]
  • これらの問題は開発版の Ruby 3.4 では修正済み
GitHubで編集を提案

Discussion