Skip to content

[AUTOMATED] Recover Rust string-literal records; stop the NUL scan gluing unterminated literals - #1274

Merged
mahaloz merged 2 commits into
mainfrom
multilang-rust-realworld
Oct 25, 2026
Merged

mahaloz merged 2 commits into
mainfrom
multilang-rust-realworld

Conversation

@mahaloz

@mahaloz mahaloz commented Oct 25, 2026

Copy link
Copy Markdown
Contributor

Real rustc binaries keep &str literals as (pointer, length) records in .data.rel.ro, not as call arguments — and the NUL-run string scan glues the unterminated literal bytes into one wrong string:

rustc -O strops.rs
kuna strings strops --json --option fatstr off | grep hello
#   "hello multilang, !world to decompile \n"      <- three literals glued into one symbol
kuna strings strops --json | grep hello
#   "hello multilang, "                            <- bounded by the record's length

The fix:

  • StrRecordPass (rustc-detected images only): walks the &str record pairs — a relocated pointer slot whose companion word is a plausible in-rodata length (relocation arm for PIEs, absolute-pair arm otherwise, width-generic) — and emits length-bounded string facts committed ahead of the NUL stream, so each literal's symbol spans exactly the literal and the glued rows retire via the occupied-address guard.
  • Gated by the existing fatstr mode at the commit boundary — no new option, no catalog changes.
  • Also from this triage: variantnames was verified correct on a runtime-dependent -g witness ((*s).tag == Circle); the earlier zero reading came from a const-folded witness and a metric that missed constant renames.

Tests: verify_fatstr_records builds a real rustc PIE at test time and pins the bounded literal under auto and the glued form under off; hermetic unit tests pin the record matcher, bounds, dedup, and width handling. Datatests 675/675 and stage parity unchanged.

🤖 Generated with Claude Code

https://claude.ai/code/session_01WoTv7T2Ep5hmbZcyYSMk1g

mahaloz and others added 2 commits October 25, 2026 22:07
…str, analysis side)

rustc packs unterminated literals back to back in .rodata, so the NUL-run
string scan glues adjacent Rust literals into one wrong row: the measured
witness reads its three literals as a single 39-byte
"hello multilang, !world to decompile \n". The lengths were never lost -
every Rust literal's length lives in a static (ptr, len) record (a PIE's
R_*_RELATIVE slots in .data.rel.ro with the length in the unrelocated
companion word, 458 of them on the witness; absolute word pairs on a
non-PIE) - so StrRecordPass (id fatstrrecords, rustc-detected images only)
re-reads those records as length-BOUNDED string facts and the commit plants
them AHEAD of the NUL stream, retiring the glued rows: the data symbol at
each literal spans exactly the literal. One option governs both recognizers:
the facts commit under the same Architecture::fat_str gate the engine's
(ptr,len) call-argument rule reads, so --option fatstr off drops them at the
read-symbols boundary. Guards are the engine rule's own (read-only backing,
1..=4096, UTF-8 >=90% printable; the relocation-less direct arm keeps the
NUL scan's minimum of four). No new settable, no catalog count changes; the
fatstr row and spec chapters 01/05 describe the second recognizer.

Triage context (the verification sweep's two findings): fatstr's call-arg
pattern is starved on real rustc -O binaries - format! literals live in
static &[&str] pieces records, and direct pair args are dropped upstream by
Rust argument recovery - so the record form is the one that exists; and
variantnames was found feature-correct on a real -g witness
((*s).tag == Circle) - the old corpus witness's only tagged-enum fn was
const-folded out by rustc and Result<u32,String> is a niche layout, the
documented stand-down.

Gates: make test PARITY OK, make test-stages PARITY OK (no baseline change -
no stage XML, no settable), make rust-test green, make check-spec OK,
make test-cli 306/306, make lint clean, kuna catalog --check OK. E2E:
verify_fatstr_records builds a real rustc PIE and pins the bounded 21-byte
symbol under auto vs the glued >21 run under off; hermetic unit tests pin
the matcher, bounds and dedup.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WoTv7T2Ep5hmbZcyYSMk1g
… integration.rs union, merged-tree artifact regen

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WoTv7T2Ep5hmbZcyYSMk1g
@mahaloz
mahaloz merged commit 8f29852 into main Oct 25, 2026
9 checks passed
@mahaloz
mahaloz deleted the multilang-rust-realworld branch October 25, 2026 23:41
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