Skip to main content

MAX_RECURSION_DEPTH

Constant MAX_RECURSION_DEPTH 

Source
pub const MAX_RECURSION_DEPTH: usize = 48;
Expand description

Maximum depth of dynamic statement-engine re-entry — command substitution ($(…)), shell-function calls, and .kai script sourcing — before a loud error is returned instead of letting the native call stack overflow (a SIGSEGV/abort with no diagnostic). Mirrors the intent of the alias re-entry cap (10) and the lexer’s MAX_PAREN_DEPTH (256): a runaway or mutually recursive script hits a catchable ceiling, not a signal.

Each level stacks the dispatch chain between re-entries. After the GH #48 allocation pass this measures ~50 KB (release) / ~57 KB (debug at the default opt-level = 1 dev profile — see the root Cargo.toml) / ~193 KB (a fully unoptimized debug build) of native stack per level, down from ~80 / ~380 KB before; the recursion_stack_cost_tests probe reports the live figure.

This cap and RECOMMENDED_STACK_SIZE are a matched pair: the cap must trip before cap × (worst-case per-level stack) can exceed the floor, so a runaway is caught, not a SIGSEGV. The worst case is the ~193 KB unoptimized figure — the opt-level = 1 dev profile above is local to this workspace and does not propagate to embedders, whose own debug builds of the kernel pay the full unoptimized cost. 48 × 193 KB ≈ 9.3 MB under the 12 MiB floor keeps the same ~1.3× margin the pre-#48 pair had (32 × 380 KB ≈ 12 MB under 16 MiB); #48’s smaller frames are what let the cap rise 32→48 and the floor drop 16→12 MiB together. The guard only fires before the stack overflows on a thread that meets that floor — this is why the REPL sizes its threads to it and embedders must too (see docs/EMBEDDING.md). Forks (background jobs, scatter workers, pipeline stages) run on fresh stacks and get a fresh counter, bounding each chain independently. GH #46 / #47 / #48.