📑

[Bug #21649] singleton_class 経由で Ractor 内でオブジェクトが書き換えられるバグ報告

に公開

[Bug #21649] Ractors can access non-shareable object through singleton classes

  • Ractor.new に渡したオブジェクトはブロック内では別のオブジェクトとして扱われるので通常は元のオブジェクトには影響は与えない
homu = "homu"

p homu.object_id # => 16

r = Ractor.new(homu) { |name|
  # スコープの外とは別のオブジェクトとして扱われる
  p name.object_id # => 24

  # 副作用があるメソッドを呼び出しても元のオブジェクトには影響は与えない
  name.upcase!
}
r.take

p homu
# => "homu"
  • これは HashArray でネストしている場合でも同様
users = [
  { name: "homu", age: 14 }
]

p users[0][:name].object_id # => 16

# ネストしたオブジェクトの場合でもコピーされる
r = Ractor.new(users) { |users|
  p users[0][:name].object_id # => 24
  users[0][:name].upcase!
}
r.take

p users[0][:name]
# => "homu"
  • なんですが次のように singleton_class を渡した場合には #attached_object 経由で元のオブジェクトを書き換えることができるというバグ報告
homu = "homu"

p homu.object_id # => 24

r = Ractor.new(homu.singleton_class) { |singleton_klass|
  # #attached_object は元々のオブジェクトを取得することができる
  p singleton_klass.attached_object # => "homu"

  # #attached_object は元々のオブジェクトを参照している
  p singleton_klass.attached_object.object_id # => 16

  # なので副作用のあるメソッドを呼び出すとスコープの外のオブジェクトも変わってしまう
  singleton_klass.attached_object.upcase!
}
r.take

p homu # => "HOMU"
  • すごいハックですね
  • 意図的に singleton_class を渡すことはあるのかなあ…
GitHubで編集を提案

Discussion