Skip to content

Fix FNV-collision symbol aliasing and memoize OP_SYMBOL#192

Merged
hadashiA merged 3 commits into
mainfrom
claude/symbol-intern-fixes
Jul 13, 2026
Merged

Fix FNV-collision symbol aliasing and memoize OP_SYMBOL#192
hadashiA merged 3 commits into
mainfrom
claude/symbol-intern-fixes

Conversation

@hadashiA

Copy link
Copy Markdown
Owner

Summary

Two Symbol-interning changes, split out from #191 as requested.

Bug fix: FNV-1a collision aliases two different symbol names

SymbolTable's dictionary key compared only the 32-bit FNV-1a hash, so two different names with colliding hashes interned to the same Symbol (~50% probability once ~65k symbols are interned; deterministic for known pairs like costarring/liquid). The generated Names.TryFind had the same flaw for hashes that map to a single known symbol: it returned the known symbol without comparing the name, so a user symbol colliding with e.g. +'s hash would alias it.

  • SymbolTable now buckets by hash with a per-bucket chain of (name, symbol) entries and always compares the actual bytes.
  • The source generator now always emits the SequenceEqual check, including single-entry hash cases.

optcarrot is unaffected (18.8 fps, matching main; checksum 59662).

Memoize OP_SYMBOL results per irep

OP_SYMBOL re-interned its pool string (FNV hash + dictionary probe) on every execution. The result is now memoized on the Irep (IrepPoolSymbolCache).

Symbols are interned per state, so the cache carries the owning state's id, and the id + symbol array live in one immutable object — a state can never observe another state's symbols through a torn owner/array pair, even if an Irep is shared between states or threads.

Note: the bundled mruby compiler emits OP_LOADSYM for symbol literals and OP_INTERN for dynamic symbols, so this path mainly matters for .mrb files produced by other mruby toolchains that do emit OP_SYMBOL.

Tests

  • InternFnv32CollidingNames: two documented FNV-1a 32-bit collision pairs intern to distinct symbols and stay findable in both directions.
  • PoolSymbolMemoAcrossStates: a hand-assembled OP_SYMBOL irep executed on two states resolves the correct name in each (fails if one state reuses the other's memo).
  • Full suite: 156 passed; all TFMs (net8.0/9.0/10.0 + netstandard2.1) build.

🤖 Generated with Claude Code

@hadashiA hadashiA merged commit fca4637 into main Jul 13, 2026
1 check passed
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