You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Recursions in rust code trigger segmentation faults. #2796
All these fail due to the same underlying reason, the rust call stack grows until a stack overflow is triggered. RustPython should be able to handle these and raise RecursionError instead, as CPython does.
Sorry I didn't see this issue before opening a duplicate!
I can imagine 3 "simple" solutions:
Add a recursion_depth private property to VirtualMachine and increment/decrement it manually on with_frame and with_recursion. This is the way CPython does it and would require a new with_recursion method which would need to be manually called by all potentially recursive rust functions.
Add an external_recursion_depth private property and increment it only on with_recursion, using vm.frames.len() + vm.external_recursion_depth to calculate the current recursion depth. This has the same caveat as 1 of needing with_recursion to be manually called.
Measure the current stack depth by actually looking at the stack, possibly using an external library such as backtrace (see this stackoverflow issue). This has the downside of being platform dependent and less deterministic.
I personally believe 1 is the way to go right now.
The complexity here appears when you hit the limit since you'd like to handle the RecursionError gracefully when you've possibly run out of stack space. I think there's a crate called stacker that might help with that (but this can be a follow up issue after basic handling of recursion is added).
The first solution is definitely the best approach, an attribute macro that basically does what Py_EnterRecursiveCall/Py_LeaveRecursiveCall would be cool.
Edit: Since you mentioned in the previous issue that you'd like to work on this, I'll go ahead and assign you.
I've found the reference of what CPython does: cpython/include/ceval.h#L49 (notice there's also a link to an email detailing it even more, including problems).
Should this issue be changed to include this or should it be in a new issue?
I also think it's better to open up for anyone to implement this, as I have other priorities and I'm not sure I have the time (although I stand ready for discussion / reviewing).
Filed #7655 with current (2026) reproducers and evidence that this is parser-layer: compile(src, '<s>', 'exec') (which does NOT go through _ast::ast_to_object) and ast.parse() crash at the identical depth threshold (~4000), showing the shared component is rustpython-ruff_python_parser itself.
Also note: #4857 (closed as fixed in 2023) still reproduces on current main — its original ast.parse('+chr(33)' * 1000000) SIGSEGVs.
Prior fixes #7630 (_ast::ast_from_object) and #7632 (json.loads) addressed downstream symptoms; the parser's own recursive descent remains unguarded.
Deep recursion raises RecursionError instead of aborting the process. The VM checks the Python recursion limit (check_recursive_call) and the C stack (check_c_stack_overflow / with_recursion) before nested native or frame entry.
Activity
pheki commentedon Oct 4, 2021
Sorry I didn't see this issue before opening a duplicate!
I can imagine 3 "simple" solutions:
recursion_depthprivate property toVirtualMachineand increment/decrement it manually onwith_frameandwith_recursion. This is the way CPython does it and would require a newwith_recursionmethod which would need to be manually called by all potentially recursive rust functions.external_recursion_depthprivate property and increment it only onwith_recursion, usingvm.frames.len() + vm.external_recursion_depthto calculate the current recursion depth. This has the same caveat as 1 of needingwith_recursionto be manually called.I personally believe 1 is the way to go right now.
DimitrisJim commentedon Oct 5, 2021
The complexity here appears when you hit the limit since you'd like to handle theRecursionErrorgracefully when you've possibly run out of stack space. I think there's a crate calledstackerthat might help with that (but this can be a follow up issue after basic handling of recursion is added).The first solution is definitely the best approach, an attribute macro that basically does what
Py_EnterRecursiveCall/Py_LeaveRecursiveCallwould be cool.Edit: Since you mentioned in the previous issue that you'd like to work on this, I'll go ahead and assign you.
pheki commentedon Oct 15, 2021
I've found the reference of what CPython does: cpython/include/ceval.h#L49 (notice there's also a link to an email detailing it even more, including problems).
Should this issue be changed to include this or should it be in a new issue?
I also think it's better to open up for anyone to implement this, as I have other priorities and I'm not sure I have the time (although I stand ready for discussion / reviewing).
changjoon-park commentedon Apr 22, 2026
Filed #7655 with current (2026) reproducers and evidence that this is parser-layer:
compile(src, '<s>', 'exec')(which does NOT go through_ast::ast_to_object) andast.parse()crash at the identical depth threshold (~4000), showing the shared component isrustpython-ruff_python_parseritself.Also note: #4857 (closed as fixed in 2023) still reproduces on current main — its original
ast.parse('+chr(33)' * 1000000)SIGSEGVs.Prior fixes #7630 (
_ast::ast_from_object) and #7632 (json.loads) addressed downstream symptoms; the parser's own recursive descent remains unguarded.youknowone commentedon Oct 6, 2026
Deep recursion raises
RecursionErrorinstead of aborting the process. The VM checks the Python recursion limit (check_recursive_call) and the C stack (check_c_stack_overflow/with_recursion) before nested native or frame entry.Closing.
— commented by Grok 4.6