Description
Found by LPM + libFuzzer + custom yul mutator (see #7947 )
{
for {let i:= 0} lt(i,2) {i := add(i,1)}
{
// x is declared and implicitly
// initialized to zero.
let x
// This assignment is not redundant
// since it is used by mstore statement
// that follows the if statement
x := 1337
if lt(i,1) {
// This assignment is redundant
x := 42
continue
}
mstore(0, x)
}
}
is incorrectly optimized to
{
let i := 0
for { } lt(i, 2) { i := add(i, 1) }
{
if lt(i, 1) { continue }
mstore(0, 0)
}
}
mstore(0, 0) should be mstore(0, 1337) instead.
In the example above, the if statement could be replaced by another branching statement e.g., switch statement with the same result.
In general, this problem manifests while the redundant assignment eliminator is visiting a continue statement inside a branch inside a for loop: Assignments to a variable in the path leading to the branching statement are also removed apart from the correct redundant assignment within the branching statement.
For example, the yul optimizer also incorrectly marks (and subsequently removes) the assignment statement directly in the for loop below leading to mstore(0, 1337) although the correct optimization should be mstore(0, 31337)
{
for {let i:= 0} lt(i,2) {i := add(i,1)}
{
let x := 1337
// This assignment is incorrectly removed
x := 31337
if lt(i,1) {
// Redundant assignment eliminator removes all
// assignments to `x` in this path (including `x := 31337`)
// when it should be removing only `x := 42`
x := 42
continue
}
mstore(0, x)
}
}
Unfortunately, this affects v0.6.0 and may warrant a bug list entry. I'm trying to understand why this was not found earlier. My intuition is that the custom mutator had a role to play by increasing the likelihood (during fuzzing) of insertion of continue statement inside for loops (which I undertook only recently).
Environment
- Compiler version: latest develop
Steps to Reproduce
$ solc --strict-assembly --optimize <test.yul>
Description
Found by LPM + libFuzzer + custom yul mutator (see #7947 )
is incorrectly optimized to
mstore(0, 0)should bemstore(0, 1337)instead.In the example above, the
ifstatement could be replaced by another branching statement e.g.,switchstatement with the same result.In general, this problem manifests while the redundant assignment eliminator is visiting a continue statement inside a branch inside a for loop: Assignments to a variable in the path leading to the branching statement are also removed apart from the correct redundant assignment within the branching statement.
For example, the yul optimizer also incorrectly marks (and subsequently removes) the assignment statement directly in the for loop below leading to
mstore(0, 1337)although the correct optimization should bemstore(0, 31337)Unfortunately, this affects
v0.6.0and may warrant a bug list entry. I'm trying to understand why this was not found earlier. My intuition is that the custom mutator had a role to play by increasing the likelihood (during fuzzing) of insertion ofcontinuestatement inside for loops (which I undertook only recently).Environment
Steps to Reproduce