plan(v0.59): add RQ-59-POPCNT (#1021) and RQ-59-TIERCENSUS — a proof sitting above a defective expansion - #1030
Merged
Merged
Conversation
…sitting above a defective expansion RQ-59-CRSWEEP verified the 11 critical/high code-review findings against the current binary. TEN were stale records. ONE was real, and it EXECUTES. RQ-59-POPCNT (#1021) — folded into v0.59 (maintainer's call; the other option was a v0.58.1 patch, precedent v0.56.2 for the #959 identity-mask OOB). The Thumb-2 i32 Popcnt expansion takes R11 as a second scratch — its own comment says so — and R11 is the WASM linear memory base. Executed differential, --cortex-m: f(0xFF) expected 1242, OBSERVED 0x20020008, i.e. popcnt(0xFF)=8 plus the word at ADDRESS 0 (the vector table's initial SP) because R11 ended as r5>>16 = 0. R11 is not in the pushed set, so it LEAKS TO THE CALLER and every later [R11] access in the call chain is wrong too. Both selector paths. i64.popcnt is unaffected (R3/R4/R5/R12, pushed) — a useful control a fix should explain. RQ-59-TIERCENSUS — the architectural finding, and it is bigger than the instance. rule_i32_popcnt IS Rocq-proved; it emits the ArmOp::Popcnt PSEUDO-OP, and the defect is in that pseudo-op's ENCODER EXPANSION. The proof is stated at pseudo-op tier, ABOVE the expansion, so it certifies "the selector emits Popcnt correctly" while the thing Popcnt BECOMES destroys the memory base. Same shape as v0.57's ArmSemantics no-oping 87 of 222 ops, one layer lower: there the MODEL did not reach the instructions, here the PROOF does not reach the expansion. TIERCENSUS is a CENSUS, not a fix (maintainer's call): of the 80 proved rules, how many emit pseudo-ops, which of those expansions are unguarded by proof / frozen anchor / execution differential, and which use registers outside the pushed set as scratch. Report and stop; the tier-boundary fix is v0.60. A small unguarded set is as valuable a result as a large one — it would mean #1021 is near a one-off rather than systemic. claim_check 49/49. Rivet artifact only, no code. Refs #1021, #242.
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.
RQ-59-CRSWEEPverified all 11 critical/high code-review findings against the current binary. Ten were stale records. One was real, and it executes.RQ-59-POPCNT (#1021) — folded into v0.59
The Thumb-2
i32.popcntexpansion takes R11 as a second scratch — its own comment says "We need a second scratch register. Use R11." — and R11 is the WASM linear memory base. The A32 transcription (#615) deliberately mirrors that register contract and inherits the defect.Executed differential (unicorn vs wasmtime,
--cortex-m):12420x20020008That's
popcnt(0xFF)=8plus the word at address 0 — the vector table's initial SP — because R11 ended asr5>>16 = 0.R11 is not in the pushed set, so it leaks to the caller and every later
[R11]access in the whole call chain reads through the garbage base. Reachable from both selector paths.i64.popcntis unaffected (R3/R4/R5/R12, all pushed) — a useful control, and a fix should explain why i64 got it right.Folded into v0.59 rather than cut as v0.58.1; the precedent for the other choice was v0.56.2, cut mid-v0.57 for the #959 identity-mask OOB.
RQ-59-TIERCENSUS — the finding behind the finding
rule_i32_popcntis Rocq-proved. It emits theArmOp::Popcntpseudo-op, and the defect lives in that pseudo-op's encoder expansion. The proof is stated at pseudo-op tier, above the expansion — so it certifies "the selector emits Popcnt correctly" while the thing Popcnt becomes destroys the memory base.Same shape as v0.57's
ArmSemantics::encode_opsilently no-oping 87 of 222 ops, one layer lower: there the model didn't reach the instructions; here the proof doesn't reach the expansion.This artifact is a census, not a fix: of the 80 proved rules, how many emit pseudo-ops; which of those expansions are unguarded by proof, frozen anchor, or execution differential; and which use registers outside the pushed set as scratch (#1021's mechanism). Report and stop — the tier-boundary fix is a v0.60 program.
A census finding the unguarded set is small is as valuable as one finding it large: it would mean #1021 is near a one-off rather than systemic, and that changes how v0.60 gets scoped.
claim_check49/49. Rivet artifact only.Refs #1021, #242.