Disassemble Beam

Elixirで :"example_#{varialble}" みたいなコードを見つけ「無尽蔵に叩かれるとGCから漏れるなあ」と思って確認した。 案の定GCから漏れるコードだった。

ErlangのatomはGC対象外なことは有名。

なのでString.to_atom:erlang.binary_to_atomは危険。 最初に言及したコードもしっかりと:erlang.binary_to_atomにトランスレートされる。

トランスレートされることの確認のためにbeamファイルをdisassembleしたので記録しておく。

逆アセコマンド

下のようなスクリプトを書いた。たまに使う気がしてgithubに起きました

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#! /usr/bin/env elixir

defmodule Disassemble do
  @moduledoc false
  @command __ENV__.file |> Path.basename()

  @usage """
  NAME:
      #{@command} -- disassemble beam

  SYNOPSIS:
      #{@command} file
  """

  def usage(), do: @usage

  def run(path) do
    result = :beam_lib.chunks(path, [:abstract_code])
    {:ok, {_, [{:abstract_code, {_, ac}}]}} = result
    IO.puts(:erl_prettypr.format(:erl_syntax.form_list(ac)))
  end
end

if 0 < length(System.argv()) do
  hd(System.argv())
  |> to_charlist()
  |> Disassemble.run()
else
    IO.puts(Disassemble.usage())
end

調査対象

下のようなコードを書いて mix compile しました。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
defmodule Example do

  @existing_atom :example_existing

  def interpolation(var) do
    :"example_#{var}"
  end

  def use_string(var) do
    String.to_atom("example_#{var}")
  end

  def use_string_for_existing(var) do
    String.to_existing_atom("example_#{var}")
  end
end

おしまい。気楽なのもあり道具の使い方のメモばっかしてて自己嫌悪に陥る。

comments powered by Disqus