Skip to main content

Overview

Monty enforces configurable resource limits to prevent untrusted code from consuming excessive resources. Without limits, malicious code could:
  • Allocate gigabytes of memory
  • Run infinite loops
  • Cause stack overflow with deep recursion
  • Generate massive strings or lists
Resource limits ensure safe execution of untrusted code.

Available Limits

Monty tracks four types of resource limits:

Max Memory

Limit total heap memory usage in bytes

Max Duration

Timeout after specified execution time

Max Allocations

Limit number of heap allocations

Max Recursion Depth

Prevent stack overflow (default: 1000)

Setting Resource Limits

Memory Limit

How It Works

Monty tracks approximate heap memory usage and checks before each allocation:

Large Result Pre-checks

Monty pre-checks operations that may produce large results (>100KB) before allocating:
The 100KB threshold (LARGE_RESULT_THRESHOLD) is compile-time and cannot be changed at runtime.

What Counts Toward Memory

Time Limit

How It Works

Monty checks elapsed time periodically during execution:

Time Check Frequency

Monty checks time every 10 VM instructions to balance:
  • Performance (checking every instruction is expensive)
  • Responsiveness (catching timeouts quickly)
Time is reset after load() when deserializing execution state. Use tracker_mut() to set a new limit when resuming.

Setting Time Limits on Resume

Allocation Limit

How It Works

Counts the total number of heap allocations:

When to Use Allocation Limits

Use allocation limits to:
  • Prevent memory fragmentation
  • Control garbage collection frequency
  • Limit total number of objects
Allocation limits are useful when combined with garbage collection intervals to control GC overhead.

Recursion Depth Limit

How It Works

Limits the maximum call stack depth:

Default Recursion Limit

If not specified, Monty uses 1000 (same as CPython’s default).
RecursionError is catchable in Python, unlike other resource errors. Untrusted code can catch and suppress RecursionError.

Platform Considerations

Very deep recursion (>500) may cause stack overflow in debug builds. Release builds handle 1000+ safely.

No Limits Mode

For trusted code, use NoLimitTracker to disable limits:
Never use NoLimitTracker with untrusted code. It only enforces recursion depth (1000).

Exception Types

Resource limit violations raise specific Python exceptions:

Handling Resource Errors

Garbage Collection

GC Intervals

Configure how often garbage collection runs:

When to Adjust GC Interval

  • Lower interval (e.g., 100): More frequent GC, lower peak memory
  • Higher interval (e.g., 10000): Less GC overhead, higher peak memory
  • No interval (None): Only run GC on allocation failure
Garbage collection only matters for code that creates reference cycles (circular references). Most code doesn’t need GC.

For User-Generated Code

For LLM-Generated Code

For Batch Processing

Monitoring Resource Usage

Track resource usage during execution:
Resource monitoring APIs are available in the Rust API. Python/TypeScript bindings may be added in future versions.

Best Practices

1

Always Set Limits for Untrusted Code

Never run untrusted code without resource limits. Always configure at least memory and time limits.
2

Set Conservative Limits Initially

Start with strict limits and increase based on actual usage patterns.
3

Monitor and Alert

Log resource limit violations to detect potential attacks or bugs.
4

Adjust Time Limits on Resume

When using iterative execution, set appropriate time limits before each resume().
5

Balance GC Frequency

Adjust gc_interval based on your memory vs. performance requirements.

Next Steps

Security Model

Learn about Monty’s sandbox isolation and security guarantees

Execution Modes

Understand run() vs start()/resume() execution