😎

[Bug #21298] TracePointでObjectSpace.allocation_class_pathの挙動が変わるバグ報告

に公開

[Bug #21298] ObjectSpace.allocation_class_path returns inconsistent results depending on TracePoint state

  • ObjectSpace.trace_object_allocations を利用すると次のように『対象のオブジェクトがどこで生成されたのか』の情報がトレースされて取得できる
# test.rb
require "objspace"

class Foo
  def test
    "hoge"
  end
end

ObjectSpace.trace_object_allocations do
  obj = Foo.new.test

  # obj が生成されたファイル名
  pp ObjectSpace.allocation_sourcefile(obj) # => "/path/to/test.rb"

  # obj が生成された行番号
  pp ObjectSpace.allocation_sourceline(obj) # => 5

  # obj が生成されたクラス
  pp ObjectSpace.allocation_class_path(obj) # => "Foo"
end
  • このチケットは『 obj が生成されたクラス』を取得する ObjectSpace.allocation_class_path に関するチケット
  • この ObjectSpace.allocation_class_path なんですが Class#new でオブジェクトを生成した場合に『その Class#new でオブジェクトを生成した』という実装に依存しており次のように Class を返すような挙動になっていた
require "objspace"

class Hoge
end

class Foo
  def test
    Hoge.new
  end
end

ObjectSpace.trace_object_allocations do
  obj = Foo.new.test

  # Foo 内でオブジェクトを生成はしているが実際には Class#new 内で生成していることになる
  pp ObjectSpace.allocation_class_path(obj)
  # => "Class"
end
  • これが開発版の Ruby 3.5-dev では『 Class#new から呼び出すフレームがなくなった』影響で Foo を返すようになった
    • これは最適化の影響を受けているらしい
require "objspace"

class Hoge
end

class Foo
  def test
    Hoge.new
  end
end

ObjectSpace.trace_object_allocations do
  obj = Foo.new.test

  # Ruby 3.5-dev では Foo を返す
  pp ObjectSpace.allocation_class_path(obj)
  # => "Foo"
end
  • これが TracePoint を有効にすると『最適化が無効になる』ので『Ruby 3.4 の挙動に戻ってしまう』というのがこのチケットで指摘されている内容になる
    • 以下のように TracePoint が無効か有効かで実行結果が変わってしまう
require "objspace"

class Hoge
end

class Foo
  def test
    Hoge.new
  end
end

ObjectSpace.trace_object_allocations do
  # TracePoint が無効な場合は Foo を返す
  obj = Foo.new.test
  pp ObjectSpace.allocation_class_path(obj)
  # => "Foo"

  # TracePoint が有効な場合は Class を返す
  TracePoint.new {}.enable do
    obj = Foo.new.test
    pp ObjectSpace.allocation_class_path(obj)
    # => "Class"
  end
end
  • TracePoint を利用している coverage を有効にしているとこれに依存しているテストが落ちてしまっていて困っているみたいですね
  • 2025-07-07T10:44:21Z master 482f4cad82 時点では開発版の Ruby 3.5-dev では『 TracePoint が有効でも Foo を返す』ような対応がされている
  • ちなみに互換性の問題でいうと非互換になってしまうんですが新しい挙動のほうが直感的で便利ということでこのチケットではそこまで言及はされていないですね
    • ただし、これの影響で power_assert のテストが落ちてしまった事象もあったので何かしら影響があるかもしれない
GitHubで編集を提案

Discussion