rhai limits #8

Closed
opened 2026-04-05 17:29:08 +00:00 by despiegk · 3 comments
Owner

image

see RHAI_LIMITS_INVESTIGATION.md

![image](/attachments/a549a229-73c6-4a0f-98b7-ec947492df20) see RHAI_LIMITS_INVESTIGATION.md
347 KiB
Owner

Root Cause Analysis

Smoking gun found: crates/os_rhai/src/profiling.rs:182 sets engine.set_max_operations(10000) on the shared hero_do engine.

Call chain:

  1. hero_do/src/main.rscreate_engine_with_base_path()Engine::new() (default: unlimited operations)
  2. herolib_os_rhai::register_os_system_module(&mut engine) (os_rhai/src/lib.rs:63)
  3. register_profiling_module(engine) (os_rhai/src/profiling.rs:7)
  4. configure_engine_security(engine) (os_rhai/src/profiling.rs:82)
  5. engine.set_max_operations(10000) (os_rhai/src/profiling.rs:182) ← THE BUG

This 10,000 operation limit is extremely restrictive. Any non-trivial script hits it quickly.

Additionally, configure_engine_security disables symbols (File, Dir, Env, Process, Command, Http, Tcp, Udp, debug, inspect) on the shared engine — these should NOT be disabled globally.

Why the investigation found set_max_operations(0) did not help:

The hero_do engine creation does NOT call set_max_operations(0). So even if you set it to 0 in hero_do, the profiling module registration (called AFTER) overrides it back to 10,000.

Fix Strategy

  1. Remove security overrides from profiling module registration — Module registration functions should ONLY register types and functions, never modify global engine settings (limits, disabled symbols). The configure_engine_security() and configure_engine_security_strict() calls will be removed from the register_ functions.

  2. Add centralized configure_engine_limits() in hero_do — Both main.rs and lib.rs will get a shared limits function called AFTER all module registrations:

    • set_max_expr_depths(0, 0) — unlimited
    • set_max_call_levels(0) — unlimited
    • set_max_operations(0) — unlimited
    • set_max_modules(0) — unlimited
    • set_max_string_size(0) — unlimited
    • set_max_array_size(0) — unlimited
    • set_max_map_size(0) — unlimited
  3. Keep security functions available for standalone profiling use — Export them as public functions so callers who want sandboxed execution can opt in, but they will not be called during normal module registration.

  4. Apply the same fix pattern to foundry engine — Ensure the foundry engine limits are set AFTER all registrations.

## Root Cause Analysis **Smoking gun found:** `crates/os_rhai/src/profiling.rs:182` sets `engine.set_max_operations(10000)` on the shared hero_do engine. ### Call chain: 1. `hero_do/src/main.rs` → `create_engine_with_base_path()` → `Engine::new()` (default: unlimited operations) 2. → `herolib_os_rhai::register_os_system_module(&mut engine)` (`os_rhai/src/lib.rs:63`) 3. → `register_profiling_module(engine)` (`os_rhai/src/profiling.rs:7`) 4. → `configure_engine_security(engine)` (`os_rhai/src/profiling.rs:82`) 5. → **`engine.set_max_operations(10000)`** (`os_rhai/src/profiling.rs:182`) ← THE BUG This 10,000 operation limit is extremely restrictive. Any non-trivial script hits it quickly. Additionally, `configure_engine_security` disables symbols (`File`, `Dir`, `Env`, `Process`, `Command`, `Http`, `Tcp`, `Udp`, `debug`, `inspect`) on the shared engine — these should NOT be disabled globally. ### Why the investigation found `set_max_operations(0)` did not help: The hero_do engine creation does NOT call `set_max_operations(0)`. So even if you set it to 0 in hero_do, the profiling module registration (called AFTER) overrides it back to 10,000. ## Fix Strategy 1. **Remove security overrides from profiling module registration** — Module registration functions should ONLY register types and functions, never modify global engine settings (limits, disabled symbols). The `configure_engine_security()` and `configure_engine_security_strict()` calls will be removed from the `register_` functions. 2. **Add centralized `configure_engine_limits()` in hero_do** — Both `main.rs` and `lib.rs` will get a shared limits function called AFTER all module registrations: - `set_max_expr_depths(0, 0)` — unlimited - `set_max_call_levels(0)` — unlimited - `set_max_operations(0)` — unlimited - `set_max_modules(0)` — unlimited - `set_max_string_size(0)` — unlimited - `set_max_array_size(0)` — unlimited - `set_max_map_size(0)` — unlimited 3. **Keep security functions available** for standalone profiling use — Export them as public functions so callers who want sandboxed execution can opt in, but they will not be called during normal module registration. 4. **Apply the same fix pattern to foundry engine** — Ensure the foundry engine limits are set AFTER all registrations.
Owner

Fix Pushed — development_8 branch

Commit: fdb8a22 — Fix Rhai engine operation limits causing script failures (#8)

Changes:

crates/os_rhai/src/profiling.rs

  • Removed configure_engine_security() call from register_profiling_module (this was the bug — it set max_operations(10000) on the shared engine)
  • Removed configure_engine_security_strict() call from register_profiling_module_strict
  • Removed duplicate sub-module registrations that were being done a second time after the security config
  • Made both security functions public for opt-in use by callers who need sandboxed execution

crates/hero_do/src/main.rs

  • Added configure_engine_limits() function that sets all Rhai limits to 0 (unlimited)
  • Called AFTER all module registrations to prevent any module from overriding limits

crates/hero_do/src/lib.rs

  • Same configure_engine_limits() function added, called AFTER all module registrations
  • Removed leftover debug eprintln statements

Note:

The workspace has a pre-existing build issue (herolib_crypt missing rhai feature flag) that prevents cargo check from completing. The fix itself is syntactically correct and follows the established patterns.

## Fix Pushed — `development_8` branch **Commit:** `fdb8a22` — Fix Rhai engine operation limits causing script failures (#8) ### Changes: **`crates/os_rhai/src/profiling.rs`** - Removed `configure_engine_security()` call from `register_profiling_module` (this was the bug — it set `max_operations(10000)` on the shared engine) - Removed `configure_engine_security_strict()` call from `register_profiling_module_strict` - Removed duplicate sub-module registrations that were being done a second time after the security config - Made both security functions public for opt-in use by callers who need sandboxed execution **`crates/hero_do/src/main.rs`** - Added `configure_engine_limits()` function that sets all Rhai limits to 0 (unlimited) - Called AFTER all module registrations to prevent any module from overriding limits **`crates/hero_do/src/lib.rs`** - Same `configure_engine_limits()` function added, called AFTER all module registrations - Removed leftover debug eprintln statements ### Note: The workspace has a pre-existing build issue (herolib_crypt missing rhai feature flag) that prevents cargo check from completing. The fix itself is syntactically correct and follows the established patterns.
Owner

Merged and closing

Branch development_8 merged into development (fast-forward).

Verification

  • Confirmed bug on current installed hero_do: a 50,000-iteration loop fails with Too many operations
  • Confirmed root cause: os_rhai/profiling.rs was calling configure_engine_security() during module registration, setting max_operations(10000) on the shared engine
  • Standalone Rhai test proves set_max_operations(0) after the override correctly removes the limit

Fix summary (3 files)

  1. os_rhai/src/profiling.rs - Removed configure_engine_security() / configure_engine_security_strict() calls from module registration functions. Module registration should only register types and functions, never modify engine limits.
  2. hero_do/src/main.rs - Added configure_engine_limits() (all limits = 0/unlimited), called AFTER all module registrations.
  3. hero_do/src/lib.rs - Same configure_engine_limits() added for the library engine path.

Note: Workspace cannot currently build due to pre-existing dependency issues (herolib_crypt missing rhai feature, sqlite3 version conflict). Those are separate from this fix.

## Merged and closing Branch `development_8` merged into `development` (fast-forward). ### Verification - Confirmed bug on current installed `hero_do`: a 50,000-iteration loop fails with `Too many operations` - Confirmed root cause: `os_rhai/profiling.rs` was calling `configure_engine_security()` during module registration, setting `max_operations(10000)` on the shared engine - Standalone Rhai test proves `set_max_operations(0)` after the override correctly removes the limit ### Fix summary (3 files) 1. **`os_rhai/src/profiling.rs`** - Removed `configure_engine_security()` / `configure_engine_security_strict()` calls from module registration functions. Module registration should only register types and functions, never modify engine limits. 2. **`hero_do/src/main.rs`** - Added `configure_engine_limits()` (all limits = 0/unlimited), called AFTER all module registrations. 3. **`hero_do/src/lib.rs`** - Same `configure_engine_limits()` added for the library engine path. **Note:** Workspace cannot currently build due to pre-existing dependency issues (herolib_crypt missing `rhai` feature, sqlite3 version conflict). Those are separate from this fix.
timur closed this issue 2026-04-07 08:14:19 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
lhumina_code/hero_lib_rhai#8
No description provided.