test(#275): execution gate for the self-contained reachable call graph#784
Merged
Conversation
…h + non-vacuity hatch The DIRECT reachable call graph on the self-contained --cortex-m image was already implemented (#235, v0.11.28): compile_all_exports walks reachable_from_exports (transitive closure over static `call`) and the cortex-m builder patches every internal BL to the emitted callee's address. What was missing was a mechanical EXECUTION gate proving the standalone image runs correctly — presence in `nm` doesn't catch a mis-patched or dropped BL. Adds an artifact-derived execution differential (reachable_callgraph_275_selfcontained_differential.py) that runs the DEFAULT self-contained image (its own Reset_Handler startup) on unicorn and compares `entry(x)` to wasmtime for 7 vectors. `entry` (the only export) calls two non-exported helpers, one of which calls a third — result 8*x+8 depends on the whole transitive closure being compiled in and every BL resolved. An unreachable `dead` helper is confirmed ABSENT (a closure, not "emit all"). Non-vacuity: a TEST-ONLY `EXPORTS_ONLY_275=1` env hatch in compile_all_exports reverts to the pre-#235 exports-only behavior (drop non-exported callees). With helpers dropped, `entry`'s BL becomes an EXTERNAL relocation and the builder degrades to a link-me ET_REL object with no Reset_Handler — not self-contained. The gate detects this (ET_REL, not ET_EXEC) and goes RED, proving it catches the historical #275 drop; GREEN with the shipped reachability walk. Default path unchanged (hatch is an env-gated no-op) → frozen anchors byte-identical. call_indirect residual unchanged: a mixed module (direct helper + call_indirect) still per-function loud-declines the call_indirect export while the reachable direct-call helpers compile — the falcon shape, silicon-gated. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L
… RED non-vacuity) Adds both directions to the trap-semantics-oracle job (already has wasmtime/unicorn/pyelftools): the GREEN gate runs the default self-contained image and diffs entry(x) vs wasmtime; the RED step asserts EXPORTS_ONLY_275=1 (pre-#235 exports-only drop) degrades to a non-self-contained ET_REL and the oracle fails — `! ...` because RED is the expected, gated outcome. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L
… binary Cold-review fix: the previous EXPORTS_ONLY_275 env hatch was a permanent "regress to the fixed #275 defect" switch in the shipped compiler — a footgun with no precedent (SYNTH_SPILL_ON_EXHAUST/SYNTH_SHIFT_MASK_ELIDE gate real alternative behaviors, not reproductions of a fixed bug). Now gated behind a non-default cargo feature `exports_only_275_probe`. The default/release build physically cannot carry the hatch (the block is `#[cfg(feature = ...)]`-compiled out; the default binary ignores EXPORTS_ONLY_275 entirely). CI builds a SEPARATE probe binary (distinct --target-dir so it never shadows the default) only for the RED non-vacuity step; every GREEN step uses the normal binary. Verified: default binary + EXPORTS_ONLY_275=1 -> GREEN (hatch inert); probe binary + EXPORTS_ONLY_275=1 -> RED (ET_REL, not self-contained). clippy clean with and without the feature. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
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.
Finding first
The direct reachable call graph on the self-contained
--cortex-mimage already works — it shipped in #235 (v0.11.28).compile_all_exportswalksreachable_from_exports(transitive closure over staticcall), and the self-contained cortex-m builder patches every internalBLto the emitted callee's address after layout. What was missing was a mechanical EXECUTION gate proving the standalone image actually runs — presence innmdoesn't catch a mis-patched or dropped BL.This PR does not implement reachability (already done) and does not close #275. The issue's actual long pole —
call_indirecttable dispatch on the self-contained path — remains silicon-gated and out of scope (a unicorn value-differential can't verify theblxThumb-bit property). It stays loud-declining.What I measured
deadhelpercall_indirectcall_indirectexport loud-declines (#275 residual). The falcon shape.So there is no direct-call bug to fix; the deliverable is the gate.
The gate (
reachable_callgraph_275_selfcontained_differential.py)Runs the DEFAULT self-contained image (its own
Reset_Handlerstartup) on unicorn and diffsentry(x)vs wasmtime for 7 vectors.entry(the only export) calls two non-exported helpers, one of which calls a third — the result8*x+8depends on the whole transitivecallclosure being compiled in and every BL resolved.Non-vacuity (proven, not asserted): a non-default cargo feature
exports_only_275_probeexposes anEXPORTS_ONLY_275=1hatch that reverts to the pre-#235 exports-only drop. With helpers dropped,entry's BL becomes an external relocation and the builder degrades to a link-me ET_REL object with noReset_Handler— not self-contained. The gate detects this and goes RED. The default/release binary physically cannot carry the hatch (#[cfg(feature = ...)]-compiled out; the default binary ignores the env var). CI wires both directions: GREEN on the normal binary, RED on a separately-built probe binary.Safety / anchors
const_cse_reduction_242,heterogeneous_table_676pass; existing#275loud-decline oracle and#758self-contained oracle pass).clippy -D warningsclean with and without the feature.Refs #275.
🤖 Generated with Claude Code
https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L