Repository navigation
fix(riscv): signed-div overflow guard must not clobber the dividend (#232, v0.11.27) - #233
Merged
Merged
Conversation
…232, v0.11.27) Regression from v0.11.26 (#231 lowest-free allocator). The i32.div_s INT_MIN/-1 overflow guard pops dividend/divisor off the vstack, then allocs scratch regs for its INT_MIN and -1 comparison constants. Since the popped operands are no longer on the vstack, live_regs didn't protect them and the lowest-free allocator reused the dividend's register for the INT_MIN constant, clobbering it before the guard's bne read it. filter_axis_decide(1000,100,500) returned 0 instead of 1088 on qemu_riscv32 (round-robin masked the latent bug in v0.11.25). Fix: alloc_temp_avoiding(&[Reg]) — the guard materializes its constants into a register that avoids the popped-but-live dividend and divisor. Applied to both the i32 guard and the i64 INT64_MIN/-1 guard (i64 path not yet reachable but same latent defect). Same liveness-across-a-branch-region class as #226. Regression proof: scripts/repro/signed_div_const.{wat,wasm} + signed_div_const_riscv_differential.py — 5/5 match wasmtime (incl. 1088 repro, INT_MIN edge, negatives). Unit test signed_div_guard_does_not_clobber_operands_232. All five prior fixtures stay bit-identical; the #231 caller-saved win is preserved. Closes #232. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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.
gale #232 — v0.11.26 regression: silent miscompile on signed div-by-const
Introduced by #231 (lowest-free allocator). The
i32.div_sINT_MIN / -1overflow guard pops its dividend/divisor off the vstack, then allocates scratch registers for theINT_MINand-1comparison constants. Because the popped operands are no longer on the vstack,live_regsdidn't protect them — the lowest-free allocator reused the dividend's register for theINT_MINconstant, clobbering it before the guard'sbne rs1, tminread it.filter_axis_decide(1000,100,500)→ 0 (expected 1088) on qemu_riscv32. Round-robin (v0.11.25) had marched to a different register and masked the latent defect — same lesson as before: an allocation-order change can expose a latent bug without being its root cause.Fix
New
alloc_temp_avoiding(&[Reg]): the guard materializes its constants into a register that avoids the popped-but-live dividend/divisor. Applied to:INT64_MIN / -1guard — same latent defect, though i64div_sis currently unreachable (i64 params/locals unimplemented), so it's defensive. (The broader i64 magnitude-reduction register discipline should be re-verified when i64 params land — noted, not claimed-fixed here.)Same liveness-across-a-branch-region class as #226.
Oracle
scripts/repro/signed_div_const.{wat,wasm}+signed_div_const_riscv_differential.py: 5/5 vectors match wasmtime — the 1088 repro, theINT_MINoverflow edge (-2147483648/?), and negative dividends.signed_div_guard_does_not_clobber_operands_232.div_const/control_step/flight_seam; RV32control_step/controller_step). The cleanup(riscv): allocator prefers caller-saved (lowest-free, not round-robin) (#230, v0.11.26) #231 caller-saved win is preserved — leaf functions still spill 0 callee-saved registers.Closes #232.
🤖 Generated with Claude Code