fix(codegen): descend through record fields when sorting machine layouts - #2880
Open
gertybotbot wants to merge 2 commits into
Open
fix(codegen): descend through record fields when sorting machine layouts#2880gertybotbot wants to merge 2 commits into
gertybotbot wants to merge 2 commits into
Conversation
Machine layouts were registered in SOURCE order while enum layouts were
already topologically sorted. `build_tagged_union_layout` sizes each state
payload via `TargetData::get_abi_size`, so a state holding another machine
(`state Holding { inner: Inner }`) was sized against a still-opaque struct
when the container was declared first, yielding a zero-sized payload array.
This is NOT fail-closed, contrary to how the gap is described in hew-lang#2864: the
reversed declaration order compiles clean, passes the opaque-member layout
guard, and SEGFAULTS at runtime. Two token-identical programs differing only
in declaration order behaved differently — `Inner` first printed correctly,
`Outer` first crashed with SIGSEGV.
Apply the same stable Kahn's topological sort `register_enum_layouts` uses,
over dependencies collected from both state and event payloads (the `<Name>Event`
companion is built in the same pass and needs the same guarantee). A layout
cycle now fails closed with a named diagnostic rather than falling back to
input order, which would silently size a participant against an opaque member.
Closes the machine-in-machine half (Gap 2) of hew-lang#2864. Gap 1 (enum payload
containing a record containing a machine) is untouched.
Tests cover BOTH declaration orders; a fix handling only one is half a fix.
Verified discriminating: with the sort reverted, the container-first test
fails while the embedded-first test still passes.
Closes the record-wrapped half ("Gap 1") of hew-lang#2864, on top of the
machine-in-machine sort from hew-lang#2879.
`register_machine_layouts` dependency-sorts machines so a container is
never sized against a still-opaque embedded machine. That walk looked for
payload field types whose name resolves to a machine — but a RECORD is not
a machine, so it missed the lookup and stopped. A machine reached only
THROUGH a record field was therefore never registered as a dependency:
state HoldingG { w: WrapG } + type WrapG { inner: InnerG }
`collect_named_machine_deps` now descends into a named type's record field
types, keyed off `pipeline.record_layouts`. Recursion is guarded by a
`visiting` stack rather than trusted: a malformed or indirect layout
terminates instead of overflowing the stack.
Unlike the direct machine-in-machine case, which segfaulted, this one
failed SILENTLY — the container-first program compiled clean, emitted no
diagnostic, produced no output, and exited 1. Token-identical programs
differing only in declaration order disagreed.
Tests cover both declaration orders and are revert-verified to
discriminate: with the record descent disabled, the container-first test
FAILS while the embedded-first test still passes.
Green: hew-codegen-rs 755 tests, all 159 tests/hew/ files,
cargo fmt --all --check, clippy --all-targets -D warnings.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes the record-wrapped half ("Gap 1") of #2864. #2879 took Gap 2 (machine-in-machine); this is the other half, and the issue can close once both land.
The gap
register_machine_layoutssorts machines so a container is never sized against a still-opaque embedded machine. That walk looks for payload field types whose name resolves to a machine — but a record is not a machine, so it missed the lookup and stopped. A machine reached only through a record field was never registered as a dependency:It fails SILENTLY — worse than Gap 2
Gap 2 segfaulted. This one produces no diagnostic, no output, and exit 1. Two programs with byte-for-byte identical token multisets, differing only in declaration order:
This is worth noting against #2864's claim that both gaps "fail closed ... do not miscompile". A silent empty exit-1 is arguably harder to diagnose than the segfault, since nothing points at layout at all.
Fix
collect_named_machine_depsnow descends into a named type's record field types, keyed offpipeline.record_layouts(already threaded into codegen). Avisitingstack guards recursion rather than trusting acyclicity — a malformed or indirect layout terminates instead of overflowing the stack.Evidence
Both declaration orders are covered, each asserting the exact payload string so a zero-sized or misaligned payload fails rather than reading back an accidental value.
Green bare (exit codes read directly, not through a pipe):
hew-codegen-rs— 755 tests, RC=0tests/hew/files — 159 ok / 0 failcargo fmt --all --check— RC=0 (caught a reflow pre-push; the lane that cost test(hew-cli): serialize wasm stdlib archive builds under the shared bootstrap lock #2874/feat(mir): implement clean_counter via faint-variable analysis #2878 a red run)cargo clippy -p hew-codegen-rs --all-targets -- -D warnings— RC=0, zero findingsmachine_in_machine_test.hewandmachine_in_record_test.hewboth still green