Skip to content

fix(vyper): model loop bounds and range arguments correctly - #3085

Open
zloglevel wants to merge 2 commits into
crytic:masterfrom
zloglevel:master
Open

fix(vyper): model loop bounds and range arguments correctly#3085
zloglevel wants to merge 2 commits into
crytic:masterfrom
zloglevel:master

Conversation

@zloglevel

Copy link
Copy Markdown

Summary

Fix Vyper loop modeling in the CFG and SlithIR generation.

Root Cause

Vyper loops were modeled with an inclusive upper bound:

counter_var <= len(iterable)
counter_var <= range_end

This caused one extra modeled iteration and could produce an invalid access at iterable[len(iterable)].

For two-argument range(start, end), Slither also initialized the artificial counter to 0 and used the first argument as the endpoint. This did not match Vyper's half-open range semantics.

Changes

  • Use counter_var < len(iterable) for array iteration.
  • Use counter_var < end for range(end).
  • Initialize the artificial counter with start for range(start, end).
  • Use the second positional argument as the endpoint.
  • Preserve Vyper's bound keyword behavior without treating it as the range endpoint.
  • Add regression coverage for dynamic array iteration and two-argument ranges.
  • Update affected Vyper CFG/SlithIR snapshots.

Testing

30 passed
ruff check passed
git diff --check passed

Signed-off-by: zloglevel <loglevel@outlook.com>
@zloglevel
zloglevel requested a review from smonicas as a code owner August 19, 2026 16:07
@CLAassistant

CLAassistant commented Aug 19, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@glarregay-tob

Copy link
Copy Markdown

Two test cases missing before this lands:

  • range(x, bound=N)bound= doesn't appear anywhere under tests/. The new branch depends on bound arriving in Call.keywords rather than args; nothing pins that.
  • range(x, x + N) — the added case only covers the literal range(5, 7). The non-literal form is the one master models as counter_var = 0 / counter_var <= x.

Both fit the existing slither_from_vyper_source fixture.

Worth pinning as a third: for i in range(-3, 2) is valid on 0.3.10 — vyper emits [repeat, range_ix0, -3, 5, 5, ...]. Master models it as counter_var <= -3 against a uint256-annotated counter, so type-based-tautology fires on correct source. This branch drops that finding.

Signed-off-by: zloglevel <loglevel@outlook.com>
@zloglevel

Copy link
Copy Markdown
Author

@glarregay-tob @smonicas Could you please take a look when you have a chance? Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants