Capstone.Config.Literal (Capstone v0.33.3)

Copy Markdown View Source

Parses Elixir source into a plain term without ever evaluating it.

target.exs is data, not code (goals.md G6): reading it must never evaluate it via Code's eval_string/1 or eval_file/1, because doing so would execute whatever its author — or a compromised generator — chose to put there. from_source/1 calls Code.string_to_quoted/1 (parse, not evaluate) and walks the resulting AST, reconstructing only a fixed whitelist of literal shapes: maps with atom keys, lists (plain or keyword), module aliases, atoms, binaries, and integers. Anything else — a function call, a variable, an operator, string interpolation, a sigil — is rejected before it is ever reduced to a value.

Accepted risk, not a gap: Code.string_to_quoted/1 itself interns an atom for every atom literal and module alias in source — this module never disables that (no static_atoms_encoder:), and Module.concat/1 mints one more per alias it reconstructs. G6's property is "never evaluates target.exs"; atom-table exhaustion is a different property this module does not claim. For a CLI reading one local, developer-authored file per invocation that is not a live threat — the concern is a server parsing unbounded attacker input on every request, not this. If that trust model ever changes, static_atoms_encoder: is the mechanism to reach for.

Summary

Types

Every reason from_source/1 can fail: unparseable source, a non-literal AST node, or a duplicate map key.

A location inside the parsed term, as a list of map keys and list indices from the root.

Functions

Parses source and reconstructs it as a plain Elixir term.

Types

error()

@type error() ::
  {:syntax_error, line :: pos_integer(), description :: String.t()}
  | {:not_literal, path(), quoted :: Macro.t()}
  | {:duplicate_key, path(), key :: atom()}

Every reason from_source/1 can fail: unparseable source, a non-literal AST node, or a duplicate map key.

path()

@type path() :: [atom() | non_neg_integer()]

A location inside the parsed term, as a list of map keys and list indices from the root.

Functions

from_source(source)

@spec from_source(String.t()) :: {:ok, term()} | {:error, error()}

Parses source and reconstructs it as a plain Elixir term.