Repository navigation
feat(sandbox): arrays and structs across the sandbox boundary - #7
Merged
Merged
Conversation
The sandboxed serverlet carried int, float, bool and string; the other three boundaries carried arrays and structs too, which undercut the claim that the boundary is chosen per module with the call site unchanged. It now carries int[], float[], bool[], and structs whose fields are numbers, booleans or such structs: the set the C ABI carries since 0.14.0, under the same rules. An array is a pointer and a count into guest memory; a struct is its repr(C) bytes, written field by field at offset_of! offsets with padding zero, so neither side reads padding or depends on the other's endianness. What the host writes for a call it frees after the call; what the guest returns the host copies and frees. The guest allocator is 8-byte aligned so numbers can be read in place. Three things the work found: The host never freed the strings it wrote into the guest. Under an 8mb cap, 20,000 one-kilobyte calls failed four times, each failure resetting the guest's state. Every allocation the host makes for a call is now released after it, and a test sends those 20,000 calls. A handler could not return its own array or string state on any boundary: `return seen` moved the value out of the actor, the child or the guest, and rustc refused in generated code. A returned state binding is now a copy; for a number that is what happened before. The secret child and sandbox guest snapshots change by one .clone() each. A sandbox handler type that cannot cross was reported by the guest crate's cargo build, after codegen, so `orchestrate check` accepted a program the build rejected. It is the typechecker's error now, and for a serverlet in an imported module, whose body the typechecker does not walk, codegen reports it before Cargo runs. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The reference, README, roadmap and design doc say what a sandboxed serverlet carries and what it does not. LIMITATIONS-notes.md is new at the root: it collects every gap found while preparing the paper, fixed or not, starting with the per-boundary table of which values cross where, which is the honest form of the unchanged-call-site claim. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This was referenced Sep 21, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Arrays and structs cross the sandbox boundary, under the rules the C ABI adopted in 0.14.0:
int[],float[],bool[]cross as a pointer and a count into guest memory.#[repr(C)]bytes, written field by field atoffset_of!offsets with padding zero, so neither side reads padding or depends on the other's endianness.orchestrate checkrejects a handler type that cannot cross, by name, as the compiler's own error. It used to surface from the guest crate's cargo build.Also fixed on the way
return seenmoved the value out of the actor, the child, or the guest and rustc refused (E0382 in-process, E0507 in the guest). A returned state binding is now a copy. Snapshots for the secret child and the sandbox guest change by one.clone()each.What still does not cross
An array of strings or structs, or a struct holding one, crosses the in-process, secret, and landline boundaries but not the sandbox.
LIMITATIONS-notes.md(new, at the root) carries the per-boundary table and everything else found on this branch, for the paper's limitations section.Tests
runtime_sandbox_serverlet_carries_arrays_and_structs: arrays and nested structs both ways, array state, a string beside an array in one call, an empty array.runtime_sandbox_frees_what_the_host_writes: 20,000 string and array calls under an 8mb cap.runtime_serverlet_handler_returns_its_state: in-process, secret, and sandboxed serverlets returning array and string state.tests/error_cases/sandbox_unsupported_type.orch: the check-time rejection.sandbox_guest(codec and helpers),secret_serverlet(one.clone()).Changelog entries are under
[Unreleased]. No version bump.🤖 Generated with Claude Code