reorganize module
This commit is contained in:
88
_archive/rhai_engine/rhaibook/safety/max-call-stack.md
Normal file
88
_archive/rhai_engine/rhaibook/safety/max-call-stack.md
Normal file
@@ -0,0 +1,88 @@
|
||||
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.
|
||||
|
||||
```rust
|
||||
// This is a function that, when called, recurses forever.
|
||||
fn recurse_forever() {
|
||||
recurse_forever();
|
||||
}
|
||||
```
|
||||
|
||||
```admonish info.side "Main stack size"
|
||||
|
||||
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).
|
||||
|
||||
```rust
|
||||
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)
|
||||
```
|
||||
|
||||
|
||||
```admonish info.small "Additional considerations"
|
||||
|
||||
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);
|
||||
~~~
|
||||
```
|
||||
|
||||
```admonish tip.small "Tip: Getting around the stack size limit"
|
||||
|
||||
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.
|
||||
```
|
Reference in New Issue
Block a user