Akatsuki Hackers Lab | 株式会社アカツキ(Akatsuki Inc.)

Akatsuki Hackers Labは株式会社アカツキが運営しています。

RubyKaigi2014 速報(3) - Symbol GC

Symbol GC - @nari3

  • SymbolをGCの対象にしたよ、という話
  • "Nakamra" の中でRuby会最強
  • 意識低いRubyistとして活動中

  • ruby-2.2.2だと作ったシンボルは開放されないけど、ruby-trunkだときちんと開放される

symbolとは?

  • primitiveなデータ

symbolの落とし穴

  • rubyは素晴らしい言語で使う人を飽きさせないために
  • 一つとして、symbolはGC
  • 脆弱性にも繋がりやすい。ユーザの入力をsymbolに変換してしまうとメモリ使用量が増加し続ける

脆弱性の例

  • RailsでDigestのヘッダ情報をhashに変換していた。whitelistにも登録されていないので、たくさんのkeyを指定するとメモリ使用量が膨大になっていく
  • @nari3さんが笹田さんのアイデアを実装
    • 「これで2.1をオワコンにしてしまった。またやってしまった」w

やっている言語、やっていない言語がある

  • 実装に依存する
  • 言語仕様に結構かかれていない

他の言語実装

  • EmacsLisp

    • unintern キーワード
  • Scala

    • GCの対象
    • 弱参照でsymbolが登録される
    • 参照が切れた時はsymbolは解消される。弱参照では簡単っぽい

Ruby

  • "sym".to_symで、frozen stringにしkeyを登録する
    • "sym"というシンボルのidは1001。ID2SYM(ID)関数でシンボルを取得出来る
  • ID: シンボルを表す一意の値
    • 比較がIDの比較だけなので、高速にできる
  • SYMBOL(value)はGCの対象にならない

なぜGCの対象にならないのか?

  • シンボルのIDをC拡張のstatic libに格納するケース

    • シンボルがGCの対象になると、sym_id(hash)も削除されちゃう
    • 新しく同じシンボルが登録されると、IDが変わってしまう。そうするとメソッド呼び出しができなくなったり、色々な不具合がでる
  • 一貫性が保てない問題

    • Ruby側で死んでしまったシンボルも

どうやってシンボルGCを作るのか?

  • Immotal symbol(C lang)とMortal Symbol(Ruby)の両方に分けてしまう

Immortal Symbol

  • 対応するIDを持っているシンボル
  • Cレベル。生き続けるシンボル
  • Immortal symbol から mortal symbol への移行は無い
  • def bar; end
    • RubyオブジェクトからIDを利用する。今と同じ

Mortal Symbol

  • IDを持たない。Rubyレベルで使われるシンボル

    • 途中で移行するケースが有る
  • "bar".to_sym

    • sym_id(hash)に、メモリのアドレスが格納される
    • 不要になった場合はsym_id(hash)から削除される
  • mortal symbol を作った時に 同名の immortal symbol があった場合

    • 既にあることを検知したら、そっちの方を使う

mortal symbol から immortal symbol に移行するケース

  • define_method("foo".to_sym){}
    • mortal symbol だが、開放すると問題になるので、immortal symbolとしてピン止めする

落とし穴

  • 全てのシンボルがGCの対象になるわけではない。immortal symbolには注意する

    • mortalからimmortalに移行するケースがある
  • ライブラリの実装でダメな具体例としては、rb_id2str(SYM2ID(sym))を使っているケース。新しいAPIを使って欲しい

    • もし見つけたら、ライブラリ作者とかに報告して欲しい

まとめ

  • "sym".to_sym -> OK(GCされる)
  • define_method("sym".to_sym){} -> NG(GCされない)

質問

  • Q: 他にimmortal symbolになるケースがある?
    • A: あまりruby書かないので思いつかないw