Mostly Automatic Translation of Language Interpreters from C to Safe Rust

2026-06-27

Authors: Bo Wang, Brandon Paulsen, Joey Dodds, Daniel Kroening

ArXiv: 2606.27122v1

PDF: Download PDF

Imagine you've got a 20-year-old C codebase running a language interpreter — something like a Python or Lua runtime. It works, but it's a minefield: pointer arithmetic, manual memory management, and the constant lurking threat of buffer overflows or use-after-free bugs that attackers love. Interpreters are an especially juicy target because they run untrusted code by design. So the dream has always been: can we just turn this into Rust? Rust gives you the same speed but with compile-time guarantees that whole categories of memory bugs simply can't happen.

The catch is that Rust enforces strict rules about ownership (who owns a piece of memory) and borrowing (who's allowed to look at or modify it, and when). C programmers blithely ignore all of this. Existing C-to-Rust tools either produce code riddled with unsafe blocks (defeating the point) or only handle tiny snippets.

This paper introduces Reboot, a mostly-automatic system that translates real interpreter codebases — between 6,000 and 23,000 lines of C — into safe Rust. The "mostly" is honest: a human still nudges it occasionally, but the bulk of the grunt work is automated. The authors tested it on six different interpreters and got working, memory-safe Rust output.

The key insight is that translation has to be ownership-aware, not just syntactic. Older tools translate C statement-by-statement, producing Rust that technically compiles but lies to the type system using escape hatches. Reboot instead analyzes how data flows through the C program — who allocates what, who frees it, who reads it — and then reconstructs that intent in Rust's ownership model. Where C says "here's a pointer, good luck," Reboot decides whether that should become an owned value, a borrowed reference, a reference-counted pointer, or something else, based on actual usage patterns in the code.

Why focus on interpreters specifically? A few reasons:

Practically, this is a meaningful step toward the long-promised future of "rewrite it in Rust" actually being feasible for legacy systems software, rather than a multi-year manual slog. It won't replace human judgment entirely, but it shrinks the effort from "rewrite from scratch" to "review and tweak."

Why it matters: Memory-safety bugs in interpreters have caused decades of security incidents, and this work makes the path from vulnerable C to safe Rust dramatically shorter for real, production-sized codebases.

All newsletters