object "ForLoopFmp" {
code { let s := datasize("ForLoopFmp_deployed") codecopy(0, dataoffset("ForLoopFmp_deployed"), s) return(0, s) }
object "ForLoopFmp_deployed" {
code {
// Establish a known free-memory pointer so FMP propagation tracks it as a constant.
mstore(0x40, 0x80)
// Dynamic trip count from calldata keeps the loop from being unrolled (which would hide the
// per-iteration re-read of the FMP).
let n := calldataload(0)
// Each iteration allocates a fresh 32-byte slot at the current FMP and bumps the pointer.
// The loop-top `mload(0x40)` must observe the bump from the previous iteration; if FMP
// propagation rewrites it to the pre-loop constant, every iteration aliases the first slot.
for { let i := 0 } lt(i, n) { i := add(i, 1) } {
let p := mload(0x40)
mstore(p, add(i, 1))
mstore(0x40, add(p, 0x20))
}
// Read back the first three allocated slots. Correct: [1, 2, 3] for n >= 3.
// With the aliasing bug: [n, 0, 0].
mstore(0x200, mload(0x80))
mstore(0x220, mload(0xa0))
mstore(0x240, mload(0xc0))
return(0x200, 0x60)
}
}
}