This repository has been archived on 2025-08-04. You can view files and clone it, but cannot push or open issues or pull requests.
rhaj/_archive/rhai_engine/rhaibook/safety/max-call-stack.md
2025-04-04 08:28:07 +02:00

2.6 KiB

Maximum Call Stack Depth

{{#include ../links.md}}

In Rhai, it is trivial for a function call to perform infinite recursion (or a very deeply-nested recursion) such that all stack space is exhausted.

// This is a function that, when called, recurses forever.
fn recurse_forever() {
    recurse_forever();
}

The main stack-size of a program is _not_ determined by Rust but is platform-dependent.

See [this on-line Rust docs](https://doc.rust-lang.org/std/thread/#stack-size) for more details.

Because of its intended embedded usage, Rhai, by default, limits function calls to a maximum depth of 64 levels (8 levels in debug build) in order to fit into most platforms' default stack sizes.

This limit may be changed via the [Engine::set_max_call_levels][options] method.

A script exceeding the maximum call stack depth will terminate with an error result.

This check can be disabled via the [unchecked] feature for higher performance (but higher risks as well).

let mut engine = Engine::new();

engine.set_max_call_levels(10);     // allow only up to 10 levels of function calls

engine.set_max_call_levels(0);      // allow no function calls at all (max depth = zero)

When setting this limit, care must be also be taken to the evaluation depth of each _statement_
within a function.

It is entirely possible for a malicious script to embed a recursive call deep inside a nested
expression or statements block (see [maximum statement depth]).

~~~rust
fn bad_function(n) {
    // Bail out long before reaching the limit
    if n > 10 {
        return;
    }

    // Nest many, many levels deep...
    if check_1() {
        if check_2() {
            if check_3() {
                if check_4() {
                        :
                    if check_n() {
                        bad_function(n+1);  // <- recursive call!
                    }
                        :
                }
            }
        }
    }
}

// The function call below may still overflow the stack!
bad_function(0);
~~~

While the stack size of a program's _main_ thread is platform-specific, Rust defaults to a stack
size of 2MB for spawned threads.

This default can further be changed such that a spawned thread has as large a stack as needed.

See [the on-line Rust docs](https://doc.rust-lang.org/std/thread/#stack-size) for more details.

Therefore, in order to relax the stack size limit for scripts, run the [`Engine`] in a separate
spawned thread with a larger stack.