Promote shifts across blocks in reconstruct_fallible_operations#1328
Promote shifts across blocks in reconstruct_fallible_operations#1328MavenRain wants to merge 2 commits into
Conversation
The shift in `out[i] = x >> y` with an overloaded `IndexMut` ends up in the block the `index_mut` call returns to, so `reconstruct_fallible_operations` does not find it, leaving the shift as `wrap.>>` behind a leftover overflow check. See issue AeneasVerif#1041. Signed-off-by: Onyeka Obi <softwareengineerasaservant@isurvivable.cv>
|
Hi! Thank you for your contribution. Would you mind re-writing your PR description yourself? It is currently decent but still full of unnecessary details that LLMs love to add. Then, instead of leaving the check, I would like to remove the check and do the arithmetic computation early instead (and store it in a fresh variable). That's always correct since the only side-effects are the panic and the memory accesses, all of which are already done by the overflow check. Also your solution is doing too much work to be correct compared to what we need: we don't need to follow the graph structure since these asserts are only ever emitted by the compiler: let's simply look for all the uses the given local in the body. Also I'd like to handle the shift checks in a single pass: iterate over the whole body looking for shifts that use the operand in question, and replace them all. To know where to insert the original computation, record the |
Rustc evaluates a shift's operands, and emits its overflow check, before computing the destination place. When that computation needs a call, e.g. `out[i] = x >> y` through an overloaded `IndexMut`, the call ends the block and the shift lands in the block the call returns to, so the per-block pattern match never pairs the check with the shift and the shift stays wrapping. Record such checks during the per-block pass, then resolve them over the whole body: find the wrapping shift by its amount, remove the check, and compute the shift early, promoted to panic-on-overflow, into a fresh local where the check used to be. A move forwards the result to the destination at the original site. This is correct because rustc has already evaluated both operands by the time control reaches the check, and the check already reads them and panics on overflow, so the early computation adds no new effect and the panic keeps its original position before the call. Fixes AeneasVerif#1041 Signed-off-by: Onyeka Obi <softwareengineerasaservant@isurvivable.cv>
b54ee5b to
165682f
Compare
Fixes #1041.
Rustc evaluates a shift's operands, and emits its overflow check, before computing the destination place. When that computation needs a call, as with the overloaded
index_mutin the issue, the call ends the block and the shift lands in the block the call returns to.reconstruct_fallible_operationsonly matches within one block, so it never pairs the check with the shift and the shift stays wrapping.We now record these checks during the per-block pass and resolve them afterwards over the whole body. For each one we find the wrapping shift by its amount, drop the check, and compute the shift early into a fresh local where the check used to be, promoted to panic on overflow. A move then carries the result to the destination back at the original site.
Doing the computation there is sound. By the time control reaches the check, rustc has already evaluated both operands, and the check itself already reads them and panics on overflow, so the early assignment introduces no new effect and the panic stays in its original position before the call.
The new UI test covers the issue's example and a variable shift amount, which now reconstruct to
panic.>>andpanic.<<. The rest of the suite is unchanged and there is no AST change, so charon-ml is unaffected.