Impact
The bound
parameter of loop ranges in Vyper v0.3.10 and newer is ignored, as it is represented by a previously unused parameter of the LLL repeat
instruction.
In the example below, bound
is supposed to break the loop if stop >= 2
, allowing to use variables in Vyper as a Turing-incomplete language.
@external
def foo(stop: uint256) -> uint256:
x: uint256 = 0
for i:uint256 in range(stop, bound = 2):
x = i
return x
Since LLL IR has no Turing-incompletness restrictions, it is compiled to a loop with a much more late exit condition. It leads to a loss of funds or other unwanted behavior if the loop body contains it.
However, more real-life use cases like iterating over an array are not affected. For instance, in the example below, an array length constant is used, which is less or equal to the constant provided as bound
.
my_array: DynArray[uint256, MAX_LEN]
for i: uint256 in range(len(my_array), bound=MAX_LEN):
...
No contracts were affected, but some of them had patterns similar to the 2nd example.
Patches
Fixed in version 1.5.3.
Workarounds
Upgrading and redeploying affected contracts is the only way.
Impact
The
bound
parameter of loop ranges in Vyper v0.3.10 and newer is ignored, as it is represented by a previously unused parameter of the LLLrepeat
instruction.In the example below,
bound
is supposed to break the loop ifstop >= 2
, allowing to use variables in Vyper as a Turing-incomplete language.Since LLL IR has no Turing-incompletness restrictions, it is compiled to a loop with a much more late exit condition. It leads to a loss of funds or other unwanted behavior if the loop body contains it.
However, more real-life use cases like iterating over an array are not affected. For instance, in the example below, an array length constant is used, which is less or equal to the constant provided as
bound
.No contracts were affected, but some of them had patterns similar to the 2nd example.
Patches
Fixed in version 1.5.3.
Workarounds
Upgrading and redeploying affected contracts is the only way.