SafeLibsBETA

SafeLibs builds memory-safe (Rust) reimplementations of critical load-bearing C/C++ libraries used throughout open source infrastructure, while attempting to preserve drop-in compatibility at compile-time and runtime.

What's this?

SafeLibs maintains Rust reimplementations of widely-used C/C++ libraries. Each port ships as a .deb that's binary-compatible with the original Ubuntu library package — same .so, same symbols, same calling conventions, so nothing downstream has to be rebuilt or relinked.

Scope

  • Rewrite widely-used C/C++ libraries in Rust for memory safety.
  • Hold the original C ABI exactly so nothing downstream has to change.
  • Match the upstream library's performance — not a soft-fork approximation of it.

Priorities, in order

  1. Drop-in compile-time and runtime compatibility.
  2. Performance.
  3. Memory safety.

Maintainability

Per-port maintainability isn't a goal. The ports are regenerable artifacts: when upstream changes, we re-run the pipeline against the new source instead of hand-patching the Rust output (eventually nightly, if the economics work out). For the same reason we don't take code PRs against the ported libraries — we don't audit the generated Rust closely enough to reason about adversarial patches. Reproducer issues are a different story; see the FAQ.

What a port provides

A completed SafeLibs port should provide:

  • Binary-compatible exported symbols.
  • C headers compatible with existing consumer builds.
  • Equivalent runtime semantics for valid inputs.
  • Upstream test-suite parity plus consumer integration validation.

How we verify it

Each port runs through the same swap test:

  • Run baseline tests against the original Ubuntu C library package.
  • Purge the original runtime/dev packages from the test environment.
  • Install SafeLibs-generated .deb replacements.
  • Re-run the exact same tests and consumer checks.

How do I use this?

Ubuntu 24.04 only for now; other distros are on the horizon someday.

  • apt — add safelibs.org/apt as a higher-priority source and apt upgrade. The SafeLibs builds ship under the same package names as the upstream Ubuntu libraries, so they replace the originals in place.
  • Docker — pre-built images with the SafeLibs ports already swapped in at hub.docker.com/r/safelibs.
  • Validator — see safelibs.org/validator to check what tests are used to validate these ports.

What's ported?

20 libraries passing validation.

Across the 20 validating ports so far: 5,330 sessions, 15.75B tokens, 897.7 agent-hours, split 1.50B recon, 2.08B setup, 6.35B port, 5.82B test.

LibraryCompleted stageSessionsTotal tokensRecon tokensSetup tokensPort tokensTest tokensAgent timeCalendar spanTotal unsafeABI unsafeOther unsafe
cjson04-test121292.5M3.8M77.1M93.7M117.8M18.1h17.1h550
giflib04-test202281.5M2.5M56.2M121.4M101.4M22.7h22.2h52251012
libarchive04-test294731.3M8.3M88.9M376.8M257.2M37.3h35.0h574348226
libbz204-test157237.0M2.3M31.5M139.4M63.7M18.1h16.8h83380
libcsv04-test96121.4M4.4M11.7M40.1M65.1M11.0h10.1h1168135
libexif04-test840986.7M3.1M117.4M149.9M716.3M73.8h92.7h1,2051,16540
libgcrypt03-port3131,420.7M514.1M54.6M236.5M615.5M77.1h90.6h2,9761,1471,829
libjansson04-test219330.8M2.9M38.1M231.7M58.1M28.6h69.6h80579015
libjpeg-turbo04-test255804.2M2.5M91.0M406.2M304.6M72.3h57.7h79178
libjson04-test143328.7M2.6M50.1M109.0M167.0M23.3h21.9h1049311
libpng04-test1701,212.5M4.2M36.3M304.9M867.0M58.2h69.2h72264478
libsdl04-test2571,245.4M3.5M209.6M719.0M313.4M56.5h46.0h47866412
libsodium04-test136276.7M6.8M22.0M190.4M57.5M18.9h18.2h53249735
libtiff04-test204577.5M6.4M23.6M478.2M69.3M30.9h27.3h3333276
libuv04-test5321,489.1M918.0M84.8M292.1M194.3M80.6h101.2h3,4103,024386
libvips04-test1861,111.9M2.7M62.1M659.4M387.7M45.1h42.5h2,8332,604229
libwebp04-test154390.8M2.9M26.9M215.8M145.1M20.9h20.4h19413361
libxml04-test4631,757.6M6.1M749.3M884.8M117.4M85.2h75.5h1,5601,425135
libyaml04-test307376.3M1.9M34.0M187.2M153.3M34.1h37.9h1266462
libzstd04-test2811,775.7M1.7M210.7M514.4M1,048.9M85.0h128.5h18315330

16,840 unsafe { ... } blocks across the validating ports — 13,080 (77.7%) forced by the C ABI, 3,760 (22.3%) other.

4 more still in progress:

How to read this table

Stage columns track each repo's 01-recon/02-setup/03-port/04-test tags. Sessions past the last completed tag count toward the next in-progress stage, so ports in earlier stages show partial column coverage. Agent time sums per-session wall clock, so parallel sessions stack as parallel agent-hours.

ABI unsafe is forced by the C surface — functions taking *const T/*mut T, extern "C" functions, or unsafe fn exposed across the FFI boundary. Other unsafe is everything else: transmutes, raw allocator handoff, intrinsics, static mut. The ABI share is the cost of drop-in compatibility; a Rust-only consumer story, or a non-ABI-stable distro target like Nix, would let a future pipeline drop a large fraction of those blocks.

How's it done?

Each port runs through a four-stage pipeline driven by Juvenal (https://github.com/zardus/juvenal), a workflow manager named after the Roman poet — riffing on "who watches the watchmen?" Each stage uses one or more Juvenal workflows to achieve and verify its goals despite agentic laziness, and each successful stage produces a git tag in the respective repo.

Juvenal leans on a behavioral quirk of coding agents: they will happily cut corners on their own work, but have no incentive to cover for another agent's shortcuts. After every implementation step, several fresh-context validation agents check the result against different criteria; anything missing bounces back to the implementer, dozens of times if necessary. The Port stage in particular doesn't share a workflow across libraries — a planning agent drafts and iteratively refines a library-specific workflow before any porting starts, because no single template fits every C library.

The full pipeline definitions live in the pipeline repo.

01

Recon

pull the original source (via Ubuntu's source packages) and existing CVEs, so the port has historical context for known non-memory issues.

02

Setup

prepare the source for porting, rewriting tests to use public library APIs (so they survive a clean reimplementation) and adding new ones, both directly against the library and through dependent applications.

03

Port

do the rust port. A planning agent first builds a library-specific workflow, then implementation and validation agents execute and check it step by step.

04

Test

exercise the port against additional client applications and the validator suite.

Who's responsible?

Other efforts

  • DARPA's TRACTOR program (Translating All C To Rust) is the broader DoD-funded push behind agentic C-to-Rust translation, and a conceptual ancestor of work like this.
  • C2Rust (Immunant) is the long-running open-source baseline for automated C-to-Rust translation. It emits literal unsafe Rust that mirrors the C source — useful as a refactoring starting point rather than a finished port.
  • A growing academic literature looks at lifting transpiled Rust toward idiomatic safe code (e.g., raw-pointer-to-reference inference), and more recently at LLM-driven C-to-Rust translation. SafeLibs sits closer to "ship a runnable .deb today" than to those formal-equivalence efforts, but draws on the same observation that machine translation gets you most of the way.

Other FAQs

Why Rust instead of some other memory-safe language?
 ▐▛███▜▌   Claude Code
▝▜█████▛▘  Optimus 9000.1 · Claude ALL_YOUR_MONEY_PLAN
  ▘▘ ▝▝    /home/YOU
                                                                                
────────────────────────────────────────────────────────────────────────────────
❯ Change this repository from Rust to YOUR_LANGUAGE_HERE
────────────────────────────────────────────────────────────────────────────────
How many tokens does this take?

Any specific answer will be obsolete in a few weeks. But if you really want the order of magnitude: about 15.75B tokens across the 20 validating ports so far, averaging out to roughly tens to hundreds of millions per library depending on size and how cleanly the C source factored. Per-library breakdown lives in The Ports.

Do you guarantee I won't get hacked?

rofl

In all seriousness: no. No human has ever read this code — not the library reimplementations, not the pipeline. Even if a port were perfect (and none are), the best it could do is fix memory-safety bugs in that one upstream library. The application using it can still be vulnerable, other libraries it links against can still be vulnerable, or the unsafe parts of these libraries can still be vulnerable, or the translation can introduce entirely new non-memory bugs, or these libraries might set your computer on fire and turn your AI agent against you. I don't use these things, and you'd be crazy to — but they're here if you want to try them out.

Are these libraries correct?

These libraries pass adapted test cases from the original projects, and work in a drop-in manner with at least one client application. Beyond that, who knows!

But should I use these libraries?

Rule of thumb: if you still have a sandbox on in your AI agent, you should probably not use these libraries. If your agent's sandbox is off, you have already made the leap!

How can I help?

Two real bottlenecks right now: humanpower and tokens.

Humanpower. Scaling agentic ports is tricky from a security standpoint — supply-chain attacks are exactly the kind of thing that gets worse as you grow. If you and I trust each other and you're interested in pitching in, get in touch. If you're in a position to fund this kind of work, sponsoring our research center is the most direct way to keep it going.

AI compute. Much of this work was done during a brief experiment where Arizona State University gave every employee infinite codex usage. ASU's infinite-Codex experiment is over and there's no great replacement queued up. If you can throw tokens our way, that's huge.

Beyond-frontier models. One obvious next move is using more agents to audit the agent-generated code, and it'd be especially cool to see what a next-generation frontier model could do here — if a frontier lab wants to collaborate on this, let us know!

Email me for more info!

What about upgrading to new library versions?

Each port is a regenerable artifact — the workflow can be rerun from scratch against a new upstream release. There's also a dedicated upgrade stage in the pipeline that's intended to be cheaper than full retranslation, though it hasn't been battle-tested yet.

Will these work outside of Ubuntu?

The current focus is Ubuntu drop-in replacements via apt, which forces strict ABI compatibility and shapes a sizable chunk of the unsafe-block count. Distributions with stricter, content-addressed semantics (like Nix) would be a better fit for agent-generated replacements; if you're interested in extending coverage there, get in touch.

Can we go beyond libraries?

Definitely a future focus, but libraries have a structural advantage that applications don't: every application that uses a library implicitly exercises it, so we get a wide pool of validation effectively for free — each downstream consumer is another test case the port has to survive. An application port has no equivalent. There's no consumer base to lean on, so we'd need a lot of extra test cases written specifically for it.

How do I report a port bug?

We can't accept code patches against the ported libraries — we don't audit the generated Rust closely enough to reason about adversarial PRs. We do accept reproducer testcases against the validator repo — the Test stage picks those up and re-runs the affected port until it passes.

What if there is already a Rust implementation?

Ideally the agents wrap it in a C ABI compatibility layer rather than redoing the work from scratch. The goal is rustification — getting C consumers off C — not reimplementation for its own sake. If a mature Rust implementation already exists, gluing a drop-in C ABI onto it is the cheaper, lower-risk path, and it inherits whatever review the existing crate has already had.

What's the license on a port?

IANAL, but: almost certainly the original library's license. A port is a derivative work — the C source shapes the Rust translation, and the test suite is lifted (and adapted) directly from upstream. I treat each port as carrying the upstream license until somebody who actually is a lawyer says otherwise.