diff --git a/tests/functional/codegen/features/iteration/test_for_range.py b/tests/functional/codegen/features/iteration/test_for_range.py index eedce46829..e64a35811d 100644 --- a/tests/functional/codegen/features/iteration/test_for_range.py +++ b/tests/functional/codegen/features/iteration/test_for_range.py @@ -414,3 +414,19 @@ def foo(a: {typ}) -> {typ}: assert c.foo(100) == 6 assert c.foo(1) == 666 assert c.foo(0) == 31337 + + +def test_for_range_signed_int_overflow(get_contract, tx_failed): + code = """ +@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 + """ + c = get_contract(code) + with tx_failed(): + c.foo() diff --git a/vyper/builtins/_convert.py b/vyper/builtins/_convert.py index adc2c233b8..156bee418e 100644 --- a/vyper/builtins/_convert.py +++ b/vyper/builtins/_convert.py @@ -10,6 +10,7 @@ bytes_data_ptr, clamp, clamp_basetype, + clamp_le, get_bytearray_length, int_clamp, is_bytes_m_type, @@ -110,8 +111,7 @@ def _clamp_numeric_convert(arg, arg_bounds, out_bounds, arg_is_signed): # out_hi must be smaller than MAX_UINT256, so clample makes sense. # add an assertion, just in case this assumption ever changes. assert out_hi < 2**256 - 1, "bad assumption in numeric convert" - CLAMP_OP = "sle" if arg_is_signed else "le" - arg = clamp(CLAMP_OP, arg, out_hi) + arg = clamp_le(arg, out_hi, arg_is_signed) return arg diff --git a/vyper/codegen/core.py b/vyper/codegen/core.py index 8c4295e5cc..29f7228406 100644 --- a/vyper/codegen/core.py +++ b/vyper/codegen/core.py @@ -1226,6 +1226,11 @@ def clamp_nonzero(arg): return IRnode.from_list(b1.resolve(ret), typ=arg.typ) +def clamp_le(arg, hi, signed): + LE = "sle" if signed else "le" + return clamp(LE, arg, hi) + + def clamp2(lo, arg, hi, signed): with IRnode.from_list(arg).cache_when_complex("clamp2_arg") as (b1, arg): GE = "sge" if signed else "ge" diff --git a/vyper/codegen/stmt.py b/vyper/codegen/stmt.py index e6baea75f7..263b0c25e8 100644 --- a/vyper/codegen/stmt.py +++ b/vyper/codegen/stmt.py @@ -10,7 +10,7 @@ IRnode, append_dyn_array, check_assign, - clamp, + clamp_le, dummy_node_for_type, get_dyn_array_count, get_element_ptr, @@ -255,7 +255,7 @@ def _parse_For_range(self): with end.cache_when_complex("end") as (b1, end): # note: the check for rounds<=rounds_bound happens in asm # generation for `repeat`. - clamped_start = clamp("le", start, end) + clamped_start = clamp_le(start, end, target_type.is_signed) rounds = b1.resolve(IRnode.from_list(["sub", end, clamped_start])) rounds_bound = kwargs.pop("bound").int_value() else: