low

single exit point not check for for loop

Reward

Total

455.95 USDC

Selected
455.95 USDC
Selected Submission

single exit point not check for for loop

Severity

Low Risk

Relevant GitHub Links

https://github.com/vyperlang/vyper/blob/3b310d5292c4d1448e673d7b3adb223f9353260e/vyper/codegen/core.py#L1049-L1070

Summary

The compiler enforces that blocks have 1 exit point. This invariant isn't checked inside for loop.

Vulnerability Details

The compiler checks that function bodies and if statements have 1 exit point: https://github.com/vyperlang/vyper/blob/3b310d5292c4d1448e673d7b3adb223f9353260e/vyper/codegen/core.py#L1049-L1070

However, as we can see in the code the For node isn't validated. Thus, contract like the following one compile fine:

@external
def returning_all_nigt_long() -> uint256:
    a: uint256 = 10
    for i in range(10):
        return 11
        a = 20
        return 12
    return a

But contracts like the following one don't compile:

@external
def i_have_so_many_exit_point_omg() -> uint256:
    a: uint256 = 10
    if a < 20:
        return 0
        a = 20
        return 11111111111111
    return 101019291

The compilation fails with:

vyper.exceptions.StructureException: Too too many exit statements (return, raise or selfdestruct).
  contract "vyper_contracts/Test.vy:4", function "i_have_so_many_exit_point_omg", line 4:4 
       3     a: uint256 = 10
  ---> 4     if a < 20:
  -----------^
       5         return 0

Impact

The single exit point is an invariant that is broken for for loops. This could be problematic if the later stages of the compilation relied on this invariant. However, such case wasn't discovered. As such we consider it as a confusing inconsistency.

Tools Used

Manual review.

Recommendations

Extend the validation for a single exit to contain also for loops.