brundonsmith / rust_lisp

A Rust-embeddable Lisp, with support for interop with native Rust functions
239 stars 19 forks source link

Stackoverflow not caught by the interpreter #31

Open chebureki opened 1 year ago

chebureki commented 1 year ago

A stack overflow is not caught by the interpreter => boom crash panic Example:

; + operator just so no tailcall optimization will help out
(defun overflow () (+ 1 (overflow)))
(overflow)

Optimally, the interpreter will return an error. You could add a depth value to the Env struct. If you try to enter a new env, and the new depth exceeds a maximum stack height, it will return an error

brundonsmith commented 1 year ago

Hmm. I'm wondering how a maximum depth would be chosen for the interpreter

I could pick an arbitrary ~reasonable maximum number, but that might be lower than necessary (or too large, where Rust runs out of memory anyway!)

I could try and base it on Rust's stack size (in bytes), but the main thread's stack size varies by the OS. You can spawn a separate thread with a specific stack size, but that gets into more complex waters. And I'd have to calculate or estimate the stack size of the actual Rust function to divide it by

The ideal solution would be to catch the stack overflow error and then handle it gracefully, but I don't think Rust exposes a way to do that

The only other thing I can think of is letting the user pass an (optional) max depth to eval when it's called

Thoughts on all that?

chebureki commented 1 year ago

I think a hard-coded/user-specified number will do the job just fine That's what python does:

import sys
sys.setrecursionlimit(1500)

One, perhaps less important, thing to consider: you should theoretically also consider the depth of the eval calls.

If you had deeply nested expressions, they would also use up the stack. A stack overflow could still occur for deeply nested code. But honestly, this has little importance. It should only happen, if you intentionally do it.