RightNow-AI/openfang · error · SandboxError

host_call: response exceeds memory bounds

Error message

host_call: response exceeds memory bounds

What it means

When the guest invokes host_call, the host serializes the response, asks the guest's exported alloc() for a destination buffer, then copies the response JSON into guest memory. If the returned pointer plus the response length exceeds the guest linear memory size, the host bails instead of writing out of bounds. This usually means the guest's alloc function returned an invalid pointer or did not reserve enough space.

Source

Thrown at crates/openfang-runtime/src/sandbox.rs:347

                    // Allocate space in guest for response
                    let alloc_fn = caller
                        .get_export("alloc")
                        .and_then(|e| e.into_func())
                        .ok_or_else(|| format_err!("no alloc export"))?;
                    let alloc_typed = alloc_fn.typed::<i32, i32>(&caller)?;
                    let ptr = alloc_typed.call(&mut caller, len)?;

                    // Write response into guest memory
                    let memory = caller
                        .get_export("memory")
                        .and_then(|e| e.into_memory())
                        .ok_or_else(|| format_err!("no memory export"))?;
                    let mem_data = memory.data_mut(&mut caller);
                    let dest_start = ptr as usize;
                    let dest_end = dest_start + response_bytes.len();
                    if dest_end > mem_data.len() {
                        bail!("host_call: response exceeds memory bounds");
                    }
                    mem_data[dest_start..dest_end].copy_from_slice(&response_bytes);

                    // Pack (ptr, len) into i64
                    Ok(((ptr as i64) << 32) | (len as i64))
                },
            )
            .map_err(|e| SandboxError::Compilation(e.to_string()))?;

        // host_log: lightweight logging — no capability check required.
        linker
            .func_wrap(
                "openfang",
                "host_log",
                |mut caller: Caller<'_, GuestState>,
                 level: i32,
                 msg_ptr: i32,
                 msg_len: i32|

View on GitHub (pinned to acf2587e46)

Solutions

  1. Fix the guest alloc export to return a valid, suitably sized region: reserve at least the requested size and grow memory (memory.grow) when the current allocation area cannot fit it
  2. Verify alloc returns a raw byte pointer, not a handle or offset relative to a heap base, matching the openfang guest ABI
  3. If the response is legitimately large, grow the guest's linear memory (compile with a larger --initial-memory or call memory.grow before host_call)
  4. Test the guest with a worst-case-size response from dispatch to catch the failure during development, not production
  5. Add a guest-side post-alloc check that ptr + size <= memory.size()*64KiB and fail fast with a clear trap

Example fix

// before (guest alloc that never grows memory)
pub extern "C" fn alloc(size: i32) -> i32 { HEAP_BASE + offset } // can overflow linear memory
// after
pub extern "C" fn alloc(size: i32) -> i32 {
    if HEAP_BASE + offset + size > mem_size() { grow_memory(size); }
    HEAP_BASE + offset
}
Defensive patterns

Strategy: validation

Validate before calling

// guest-side, after alloc and before host_call
let mem_size = memory.size() * 65536;
assert!(ptr >= 0 && (ptr as u64) + response_bytes.len() as u64 <= mem_size as u64, "alloc returned invalid region");

Type guard

fn alloc_result_ok(ptr: i32, need: usize, mem_len: usize) -> bool {
    ptr >= 0 && (ptr as u64).checked_add(need as u64).map_or(false, |end| end <= mem_len as u64)
}

Try / catch

match result {
    Err(e) if e.to_string().contains("response exceeds memory bounds") => {
        eprintln!("guest alloc returned too-small/invalid region: {e}");
        // grow guest memory or fix alloc(); retry once after fix
    }
    other => other?,
}

Prevention

When it happens

Trigger: The guest alloc() returns a pointer near the end of linear memory without growing memory; alloc ignores its size argument; alloc is missing/buggy in a hand-written guest; the response payload is large and the guest memory was not grown; pointer arithmetic in the guest wraps (i32 overflow).

Common situations: Custom guest runtimes with minimal allocators that return fixed offsets; responses that grew after an API change (bigger JSON payloads) while the guest heap did not; guests compiled for a different ABI where alloc returns a tagged/handle value instead of a raw pointer; running with a reduced initial memory limit in the sandbox config.

Related errors


AI-assisted analysis of RightNow-AI/openfang@acf2587e46 (2026-09-02). Data as JSON: /api/errors/191c89d416ce111d. Report an issue: GitHub.