Skip to content

Deeply nested array type crashes with raw RecursionError #5157

Description

@researchzero-sec

Version Information

  • vyper Version (output of vyper --version): 0.4.4+commit.bdf00d31
  • OS: Linux Ubuntu Jammy
  • Python Version: Python 3.11

What's your issue about?

A deeply-nested array type annotation that CPython parses fine overflows Vyper's own recursive AST-annotation visitor and crashes the compiler with a raw Python RecursionError instead of a clean vyper.exceptions diagnostic. AnnotatingVisitor.generic_visit calls super().generic_visit(node) once per AST-node depth (vyper/ast/parse.py:258). This runs inside annotate_python_ast (called at parse.py:103), which is outside the python_ast.parse try/except at :80-81, and the only enclosing handler parse_to_ast (:31-33) catches SyntaxException — so the RecursionError (a RuntimeError subclass) escapes all handlers and reaches the user with no vyper.exceptions class and no source location. Both a ~500-level static array (uint256[1]…[1]) and a ~200-level DynArray[DynArray[…]] trigger it; a nested HashMap instead hits a CPython-parse SyntaxException that is handled cleanly, so the leak is specific to array-subscript nesting that reaches the annotation visitor.

Code that produces the failing contract:

# both crash with `RecursionError: maximum recursion depth exceeded`
print("x: " + "uint256" + "[1]" * 500 + "\n@external\ndef f(): pass")
print("x: " + "DynArray[" * 200 + "uint256" + ", 2]" * 200 + "\n@external\ndef f(): pass")

Command and full output:

$ vyper nest.vy
RecursionError: maximum recursion depth exceeded     # bare — no vyper.exceptions, no location

Source-level evidence:

# vyper/ast/parse.py
#   :31-33  parse_to_ast:  try: ... except SyntaxException as e: ...   # catches Vyper's class only
#   :79-81  try: py_ast = python_ast.parse(...) except SyntaxError     # CPython parse site
#   :103    annotate_python_ast(...)            # OUTSIDE the :80 try/except
#   :205    class AnnotatingVisitor.generic_visit(self, node):
#   :258        node = super().generic_visit(node)   # <- RecursionError on deep nesting, unguarded

How can it be fixed?

A sys.setrecursionlimit-aware guard or a typed exception (e.g. StructureException("type nesting too deep")) raised from the annotation pass would convert the raw RecursionError into a clean Vyper diagnostic with a source location.

Activity

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

Metadata

Metadata

Assignees

Labels

bug - UXa bug related to UX

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions