vyperlang / vyper

Pythonic Smart Contract Language for the EVM
https://vyperlang.org
Other
4.87k stars 796 forks source link

Loop Iterator Overflow Signed Type #3963

Closed cyberthirst closed 6 months ago

cyberthirst commented 6 months ago

Version Information

When a bound is specified, the range() built-in checks at runtime that ["assert", [le, start, end]]. However, if the type of the loop iterator, is a signed integer, the check is not always correct as le here performs an unsigned integer comparison and not a signed one. This means that:

If the iterator type is int256 it is possible to overflow 256 bits while looping if end is negative and start is positive.

POC

For example, calling the function foo in the following contract returns [57896044618658097711785492504343953926634992332820282019728792003956564819967, -57896044618658097711785492504343953926634992332820282019728792003956564819968, -57896044618658097711785492504343953926634992332820282019728792003956564819967]

@external
def foo() -> DynArray[int256, 10]:
    res: DynArray[int256, 10] = empty(DynArray[int256, 10])
    x:int256 = max_value(int256)
    y:int256 = min_value(int256)+2
    for i:int256 in range(x,y , bound=10):
        res.append(i)
    return res

credits: @trocher

charles-cooper commented 6 months ago

this was fixed in b4429cf83ab75c653c1d5a65a567fa56256aaada right?

https://github.com/vyperlang/vyper/blob/b4429cf83ab75c653c1d5a65a567fa56256aaada/tests/functional/codegen/features/iteration/test_for_range.py#L419-L432

charles-cooper commented 6 months ago

confirmed with @trocher, fixed in #3814