2021/08/13 今週の気になった bugs.ruby のチケット

今週は instance_execMethod#to_proc を渡すと意図しない例外が返ってくるというバグ報告や Ruby 3.0.2 で Hash#transform_keys! を呼び出すとメモリリークをするという報告がありました。

[Feature #18070] attr should be removed

  • 1.9 から非推奨だった attr を消すチケット
  • attr は以下のようなメソッド
class User
  # getter のみ定義される
  attr :id

  # true を渡すと setter も定義される
  attr :name, true
end
  • 非推奨なのは第二引数の true / false を渡すことなので attr 自体は特に問題なさそう?

[Feature #1806] instance_exec is just ignored when the block is originally a method

  • Method#to_proc の結果は元のコンテキスト情報を持っているので次のようなコードは失敗する
f = -> (x) { a + x }

class A
  def a
    1
  end
end

# これは f 内の a は A#a を参照する
A.new.instance_exec(1, &f) # => 2


class B
  def b(x)
    a + x
  end
end

# B#method の場合の場合は a が B#a を参照する
proc = B.new.method(:b).to_proc
# なのでエラーになる
A.new.instance_exec(1, &proc)
# => undefined local variable or method `a' for #<B:0x00007fdaf30480a0> (NameError)
  • このチケットの提案自体は NameError になるのではなくて ArgumentError になるべきでは?という内容
  • これ自体は期待する挙動らしい
  • なぜなら Method#to_proc の実装は以下のようになっており結果的に Method#call を呼んでいるから
class Method
  def to_proc
    method = self
    ->(*args, **kwargs, &block) do
      # ここで `B#b` が呼ばれるため結果的に NameError になる
      method.call(*args, **kwargs, &block)
    end
  end
end

[Bug #18065] 3.0.2 - possible memory leak in Hash#transform_keys!

  • 次のようなコードを Ruby 3.0.2 で実行するとメモリリークしてメモリを大量に消費するらしい
    • これは Ruby 3.0.2 で再現して Ruby 3.0.1 では問題ない
h = { value1: 1, value2: 2 }
loop { h.transform_keys!(&:to_s) }
  • この問題は既に最新版で修正済み