# How to compile and run C code in a sandbox Write the source into a Linux microVM, compile it with gcc there, and run the binary with a time limit and the internet off. **On Runtime there is nothing to install: gcc and make are in every sandbox.** Each sandbox is a Firecracker microVM running Ubuntu 24.04.5 with build-essential, so a C file compiles in the first command after create. A new sandbox took 351 ms from the create request to its first Python result at the median, measured on 24 September 2026 ([speed](/docs/speed)), which makes a fresh machine per program practical. ## Why C needs a real boundary C code can overflow a buffer, write through a stray pointer, fork until the process table is full or spin forever. In a container all of that runs on the host's kernel. In a Runtime sandbox it runs on the microVM's own kernel, with CPU, memory, network and cost enforced on the host, outside the VM ([security](/docs/security)). The worst a bad program can do is break a machine you were going to throw away. ## What is installed and what to add | Tool | In the default image | Ubuntu 24.04 package, checked 25 September 2026 | Add it with | | -------------- | --------------------- | ----------------------------------------------- | ---------------------------------------- | | gcc, make | Yes (build-essential) | gcc-13 13.3.0, build-essential 12.10 | nothing | | clang | No | clang-18 18.1.3 | `sudo apt-get install -y clang` | | CMake | No | cmake 3.28.3 | `sudo apt-get install -y cmake` | | gdb | No | gdb 15.0.50 | `sudo apt-get install -y gdb` | | Valgrind | No | valgrind 3.22.0 | `sudo apt-get install -y valgrind` | | SQLite headers | No | libsqlite3-dev 3.45.1 | `sudo apt-get install -y libsqlite3-dev` | `sudo` works without a password inside the sandbox ([the sandbox environment](/docs/sandbox-environment#what-is-installed)). ## Compile and run a program Write the file, compile it, and run the binary in two separate commands, so a compiler error and a crash come back as different results. ```ts import { Sandbox } from "withruntime"; const source = `#include int main(void) { long total = 0; for (int i = 1; i <= 100; i++) total += i; printf("%ld\\n", total); return 0; } `; await using sbx = await Sandbox.create({ network: { internet: false }, timeoutSeconds: 300, onLeaseEnd: "stop", }); await sbx.files.write("/workspace/main.c", source); const build = await sbx.exec(["gcc", "-O2", "-Wall", "-Wextra", "-o", "main", "main.c"]); if (build.exitCode !== 0) throw new Error(build.stderr); const run = await sbx.exec(["./main"], { timeoutMs: 10_000 }); console.log(run.exitCode, run.timedOut, run.stdout); // 0 false 5050 ``` ```python from withruntime import Sandbox source = """#include int main(void) { long total = 0; for (int i = 1; i <= 100; i++) total += i; printf("%ld\\n", total); return 0; } """ with Sandbox.create(network={"internet": False}, timeout_seconds=300, on_lease_end="stop") as sbx: sbx.files.write("/workspace/main.c", source) build = sbx.exec(["gcc", "-O2", "-Wall", "-Wextra", "-o", "main", "main.c"]) if build.exit_code != 0: raise SystemExit(build.stderr) run = sbx.exec(["./main"], timeout_ms=10_000) print(run.exit_code, run.timed_out, run.stdout) ``` - **An array runs the program directly**, with no shell, so file names and arguments from a model cannot inject commands ([run commands](/docs/javascript#run-commands)). - **A program that never ends** returns `timedOut: true` with its output so far. The default limit is 60 seconds. - **A program that prints forever** is capped: a result keeps at most 64 KiB of stdout and 64 KiB of stderr, and says what it dropped. - **gcc's messages go to stderr.** Send them back to the model as they are; it can fix its own code from them. ## Catch memory bugs with sanitizers GCC's AddressSanitizer detects out-of-bounds and use-after-free bugs, and UndefinedBehaviorSanitizer detects undefined behaviour at run time, both from compiler flags ([GCC instrumentation options](https://gcc.gnu.org/onlinedocs/gcc/Instrumentation-Options.html)). Nothing extra is installed: ```ts import { Sandbox } from "withruntime"; await using sbx = await Sandbox.create({ network: { internet: false } }); await sbx.files.write( "/workspace/bug.c", "#include \nint main(void) { int *a = malloc(4 * sizeof *a); a[4] = 1; free(a); return 0; }\n", ); await sbx.exec(["gcc", "-g", "-fsanitize=address,undefined", "-o", "bug", "bug.c"], { check: true, }); const run = await sbx.exec(["./bug"], { timeoutMs: 30_000 }); console.log(run.exitCode, run.stderr.slice(0, 2000)); // the sanitizer's report ``` For Valgrind or gdb, install them once per sandbox, or bake them into an image as below. ## Build a Makefile project Upload a folder and run `make` in it. The upload travels as one archive and keeps file modes, so scripts stay executable. ```python check from withruntime import Sandbox with Sandbox.create(network={"internet": False}) as sbx: sbx.files.upload("./project", "/workspace/project") build = sbx.exec(["make", "-j2"], cwd="/workspace/project", timeout_ms=300_000) tests = sbx.exec(["make", "test"], cwd="/workspace/project", timeout_ms=120_000) print(build.exit_code, tests.exit_code, tests.stdout[-2000:]) ``` ## Start every sandbox with your toolchain A [custom image](/docs/images#build-from-an-image-or-a-recipe) installs the extra tools once. Building it is free; a stored image is charged on its size. ```ts check import { Runtime } from "withruntime"; const runtime = new Runtime(); await runtime.images.build({ name: "c-tools", recipe: { apt: ["clang", "cmake", "gdb", "valgrind"] }, }); await using sbx = await runtime.sandboxes.create({ image: "c-tools", network: { internet: false }, }); console.log((await sbx.exec(["valgrind", "--version"])).stdout); ``` ```bash no-run runtime image build --apt clang,cmake,gdb,valgrind --name c-tools ``` ## What it costs Runtime bills the CPU a sandbox uses, at $0.025 per vCPU-hour, and memory at $0.0075 per GiB-hour. A compile keeps a core busy for a moment; waiting costs the floor of a twentieth of a vCPU. A 2 vCPU, 4 GiB sandbox costs $0.03125 an hour idle and $0.08 an hour with both cores busy ([pricing](/docs/pricing)). New accounts get 50 free sandbox hours, no card: ```bash no-run npx withruntime sandbox run --trial -- gcc --version ``` For C++, see [how to run C++ code in a sandbox](/languages/cpp). To grade many submissions, see [grading student code](/use-cases/grade-student-code), and for code a model wrote, [running untrusted LLM code](/use-cases/run-untrusted-llm-code). ## Sources Checked 25 September 2026. - Ubuntu 24.04 (noble) packages: [gcc-13](https://packages.ubuntu.com/noble/gcc-13), [build-essential](https://packages.ubuntu.com/noble/build-essential), [clang-18](https://packages.ubuntu.com/noble/clang-18), [cmake](https://packages.ubuntu.com/noble/cmake), [gdb](https://packages.ubuntu.com/noble/gdb), [valgrind](https://packages.ubuntu.com/noble/valgrind), [libsqlite3-dev](https://packages.ubuntu.com/noble/libsqlite3-dev) - [GCC instrumentation options](https://gcc.gnu.org/onlinedocs/gcc/Instrumentation-Options.html) Facts on this page were checked on 25 September 2026.