😺

[Bug #21267] Class#allocate に関するバグ報告

に公開

[Bug #21267] respond_to check in Class#allocate is inconsistent

  • Class#allocate では rb_obj_respond_to(klass, rb_intern("allocate")) のようなチェックを行っており #respond_to?.allocate が呼び出せないような状況であればエラーになるようになっている
    • 要はクラス側で .allocateprivate 等で呼び出せない状況になっている場合は親クラスのメソッドである Class#allocate が失敗するようになっている
  • これは以下のように Class#allocate#bind_call 等からの呼び出しを禁止しているのが理由みたいです
class X
  class <<self
    undef_method :allocate
  end
end

# Class#allocate を直接呼び出すようなコード
# error: calling X.allocate is prohibited (TypeError)
Class.instance_method(:allocate).bind_call(X)
  • 意図的にこういう呼び出しを禁止しているのですが次のようにサブクラスで Class#allocate を再定義するとこれが突破されてしまうというバグ報告
class X
  class <<self
    undef_method :allocate
  end
end

class Y < X
  def self.allocate
  end
end

# no error
# Y.allocate が定義されているので `respond_to?` で呼び出せる判定になる
# しかし、実際には Class#allocate が呼び出されてしまう
Class.instance_method(:allocate).bind_call(Y)
  • チケットの内容としてはこのチェック自体を削除したいみたいですね
    • モチベーションとしてはこのチェックがパフォーマンスに影響があるので削除したいみたい
  • これなんですが最終的には開発版の Ruby 3.5-dev では『rb_obj_respond_to(klass, rb_intern("allocate")) のチェック自体を削除する』という対応になりました
class X
  class <<self
    undef_method :allocate
  end
end

Class.instance_method(:allocate).bind_call(X)
# Ruby 3.4 => error: calling X.allocate is prohibited (TypeError)
# Ruby 3.5 => no error
GitHubで編集を提案

Discussion