Skip to content

fix(beam): escape quotes and backslashes in quoted atoms - #4866

Merged
dbrattli merged 1 commit into
mainfrom
fix/beam-quoted-atom-escaping
Aug 1, 2026
Merged

fix(beam): escape quotes and backslashes in quoted atoms#4866
dbrattli merged 1 commit into
mainfrom
fix/beam-quoted-atom-escaping

Conversation

@dbrattli

@dbrattli dbrattli commented Aug 1, 2026

Copy link
Copy Markdown
Collaborator

Problem

quoteErlangAtom wraps a name in single quotes without escaping its contents. A quoted Erlang atom reads the same escape sequences a string does, so two characters break it — and [<CompiledName>] reaches the atom text verbatim (via unionCaseTagName), which makes both user-reachable:

type Quoted =
    | [<CompiledName("it's")>] Apostrophe of int
    | [<CompiledName("back\\slash")>] Backslash of int
'it's'          %% syntax error — the ' closes the atom early
'back\slash'    %% compiles, but `\s` is Erlang's escape for a space

The second is the one that matters: it compiles cleanly and yields the atom back lash. Codegen and the erl_tag in reflection metadata both go through this function, so they agree on the wrong name and nothing surfaces the mismatch.

Fix

Escape \ then ' inside the quotes (backslash first, or the ones the second replace adds get escaped again).

Scope is narrow: quoteErlangAtom is only reached from AtomLit printing in ErlangPrinter. Module, export and function-clause names print raw and always come from sanitizeErlangName, which strips these characters already.

Test

tests/Beam/ReflectionTests.fs gains a DU carrying both hostile [<CompiledName>]s, next to the existing CompiledName/erl_tag regression test. It covers pattern matching and a MakeUnion → match round-trip, so the reflection tag has to land on the same atom codegen emits.

Verification

  • Reproduced on the branch baseline first: the generated module failed to compile, and 'back\slash' was visible in the output.
  • After the fix, erlang:atom_to_binary round-trips it's, back\slash and both'and\ exactly.
  • Beam suite: 2659 passed, 0 failed (.NET 2637 / Erlang 2659), plus the entry-point program tests. Fantomas clean.

🤖 Generated with Claude Code

`quoteErlangAtom` wrapped a name in single quotes without escaping its
contents, but a quoted atom reads the same escape sequences a string does.
A `[<CompiledName>]` reaches the atom text verbatim, so both characters are
user-reachable:

  [<CompiledName("it's")>]        ->  'it's'         syntax error
  [<CompiledName("back\slash")>]  ->  'back\slash'   silently `back lash`

The second is the worse one: `\s` is Erlang's escape for a space, so the
module compiles and the atom is simply not the one that was asked for.

Escape `\` then `'`. Only `AtomLit` literals go through this function;
module, export and function-clause names print raw and always come from
`sanitizeErlangName`, which strips these characters already.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@dbrattli
dbrattli merged commit 5d5231b into main Aug 1, 2026
41 checks passed
@dbrattli
dbrattli deleted the fix/beam-quoted-atom-escaping branch August 1, 2026 08:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant