Organizations: Korea University, South Korea · University of Houston, United States · State University of New York Korea, South Korea · Virginia Tech, United States
We present Encapsulated Substitution and Agentic Refinement on a Live Scaffold for Safe C-to-Rust Translation, a two-phase pipeline for translating real-world C projects to safe Rust. Existing approaches either produce unsafe output without memory-safety guarantees or translate functions in isolation, failing to detect cross-unit type mismatches or handle unsafe constructs requiring whole-program reasoning. Furthermore, function-level LLM pipelines require coordinated caller updates when type signatures change, while project-scale systems often fail to produce compilable output under real-world dependency complexity. Encrust addresses these limitations by decoupling boundary adaptation from function logic via an Application Binary Interface (ABI)-preserving wrapper pattern and validating each intermediate state against the integrated codebase. Phase 1 (Encapsulated Substitution) translates each function using an ABI-preserving wrapper that splits it into two components: a caller-transparent shim retaining the original raw-pointer signature, and a safe inner function targeted by the LLM with a clean, scope-limited prompt. This enables independent per-function type changes with automatic rollback on failure, without coordinated caller updates. A deterministic, type-directed wrapper elimination pass then removes wrappers after successful translation. Phase 2 (Agentic Refinement) resolves unsafe constructs beyond per-function scope, including static mut globals, skipped wrapper pairs, and failed translations, using an LLM agent operating on the whole codebase under a baseline-aware verification gate. We evaluate Encrust on 7 GNU Coreutils programs and 8 libraries from the Laertes benchmark, showing substantial unsafe-construct reduction across all 15 programs while maintaining full test-vector correctness.
Figures & tables
Figure 1. Encrust two-phase translation pipeline. Phase 1 (left): for each function, the LLM generates a wrapper/safe-function pair verified through a compile-and-test loop; successfully translated pairs are collected into rust_safe/ . After all functions are translated, type-directed wrapper elimination rewrites call sites to invoke safe functions directly, yielding a wrapper-free crate rust_safe_remap/ . Phase 2 (right): an LLM agent equipped with 17 tools resolves the unsafe patterns deferred from Phase 1— static mut globals, unsafe-cast wrapper pairs, failed struct translations, and functions that exhausted the per-function retry budget—through an iterative loop governed by a compile-and-test verification gate.
Category
Tool
Description
Navigation
grep
Regex search across the workspace; returns matching file:line pairs with surrounding context
read_file
Read file contents with an optional start/end line range
read_function
Extract a complete function body by brace-depth counting
get_function_signatures
List all function signatures declared in a given file
list_files
Enumerate all .rs source files in the workspace
Modification
replace
Exact-match replacement of a unique string in a single file
Table 1. Phase 2 tool suite (17 tools). All tools operate on the working copy of rust_safe_remap/ .
Program
LoC
Functions
Covered
Test scripts
split
13,848
207
73
12
pwd
5,859
127
16
2
cat
7,460
166
37
4
truncate
7,181
124
33
8
uniq
8,299
167
34
3
tail
14,423
266
76
30
Table 2. GNU Coreutils benchmark statistics ( Nitin et al., 2025 ) . “Covered” = functions exercised by the test suite.
Library
LoC
Functions
Covered
Test inputs
tulipindicators
12,565
270
211
1,000
optipng
106,123
495
224
1,000
bzip2
4,417
65
31
1,000
snudown
5,426
140
72
1,000
lil
3,565
148
72
1,000
genann
410
13
7
1,000
Table 3. Laertes benchmark statistics ( Emre et al., 2021 ) . Test inputs are collected via AFL++ fuzzing (1,000 per library).
Program
System
Ptr.Decl ↓
Ptr.Deref ↓
Unsafe LoC ↓
Unsafe Cast ↓
Unsafe Call ↓
Comp.Rate ↑
Correct. ↑
Clippy ↓
cat
C2Rust
192
317
5,625
3,116
1,038
N/A
100%
546
C2SaferRust
120
240
4,189
1,992
912
75.3%
100%
239
EvoC2Rust
81
231
2,338
1,082
525
64%
0%
N/A
Encrust
95
170
3,407
1,463
1,076
95.8%
100%
211
head
C2Rust
192
442
6,245
3,488
1,378
N/A
100%
410
C2SaferRust
141
351
4,699
2,464
1,189
69.9%
100%
247
Table 4. Safety and correctness metrics on the GNU Coreutils benchmark. Columns (all ↓ lower is better unless noted): Ptr.Decl = raw pointer declarations; Ptr.Deref = raw pointer dereferences; Unsafe LoC = unsafe lines of code; Unsafe Cast = unsafe type casts; Unsafe Call = unsafe call expressions; Comp.Rate ( ↑ ) = fraction of LLM-translated functions that compiled (N/A for systems without LLM function translation); Correct. ( ↑ ) = test-script pass rate; Clippy = cargo clippy warning count. EvoC2Rust Correct. = 0% and Clippy = N/A because the translated project does not compile. Best value per metric per program bolded ; second-best underlined .
Library
System
Ptr.Decl ↓
Ptr.Deref ↓
Unsafe LoC ↓
Unsafe Cast ↓
Unsafe Call ↓
Comp.Rate ↑
Correct. ↑
Clippy ↓
bzip2
C2Rust
147
3,614
9,304
6,601
1,686
N/A
100%
254
C2SaferRust
85
2,217
7,688
3,397
1,252
57.58
100%
417
EvoC2Rust
65
391
1,459
548
327
83.00
0%
N/A
Encrust
79
384
1,907
886
572
93.94
100%
146
genann
C2Rust
48
158
557
231
116
N/A
100%
32
C2SaferRust
38
127
479
174
102
57.14
100%
29
Table 5. Safety and correctness metrics on the Laertes benchmark. Column definitions as in Table 4 . Comp.Rate : fraction of LLM-translated functions that compiled within the retry budget ( Encrust and EvoC2Rust ); N/A for C2Rust (no LLM translation). Correct. : test-vector pass rate (100% = all inputs match C reference output). All 8 libraries have Encrust results. Best value per metric per library bolded ; second-best underlined .
Suite
Configuration
Ptr.Decl
Ptr.Deref
Unsafe LoC
Unsafe Cast
Unsafe Call
Clippy
Coreutils
C2Rust
1,572
3,471
50,668
27,647
10,414
2,951
Encrust Phase 1
886
1,585
27,424
11,227
9,659
1,463
Encrust (Phase 1+2)
829
1,489
25,724
10,626
9,336
1,495
Laertes
C2Rust
2,991
14,177
87,501
50,652
15,213
7,174
Encrust Phase 1
2,269
8,278
69,009
36,107
13,795
6,465
Encrust (Phase 1+2)
2,081
4,729
60,190
30,041
12,482
6,453
Table 6. Ablation: incremental contribution of each phase, aggregated over the Coreutils (7 programs) and Laertes (8 libraries) benchmarks. Encrust Phase 1 = after Type-Directed Wrapper Elimination only; Encrust (Phase 1+2) = full pipeline. All metrics ↓ lower is better.
Task type
Disc.
Compl.
Failed
Rate
Avg. iters
static_mut
363
227
136
62.5%
21.8
wrapper_removal
454
347
107
76.4%
20.6
struct_migration
23
21
2
91.3%
10.7
struct_use_migrate
15
14
1
93.3%
3.8
function_translate
263
174
89
66.2%
23.7
dead_code
15
7
8
46.7%
18.3
Table 7. Phase 2 task completion breakdown aggregated over all 15 programs (7 Coreutils + 8 Laertes). Rate = Completed / Discovered. Avg. iters = mean agentic loop iterations per completed task.
Code translation converts programs between languages, frameworks, and representations while aiming to preserve behavior and sometimes improve safety or performance.
Translating C programs to safe Rust is challenging owing to significant differences in typing constraints, ownership, and borrowing rules. Interpreter programs are particularly important targets for such translation, as they often handle untrusted inputs and suffer from memory-related vulnerabilities. We present Reboot, a mostly-automatic technique that translates real-world interpreter programs from C to safe Rust. Using Reboot, we have translated six interpreters ranging from 6k to 23k lines of C code to safe Rust, with each translation requiring only 1 to 11 brief user interventions. All translations pass 100% of the provided test suites, and achieve 62%--92% pass rates on separately created validation tests that were never exposed to the system. A security case study on mujs shows that memory vulnerabilities such as heap buffer overflows and use-after-free present in C are eliminated in the safe Rust translation. Two ideas underpin Reboot. First, feature reduction decomposes the translation by program features, creating a sequence of milestones where each is a complete, testable program; the translation starts from the simplest version and incrementally restores features, with each milestone validated before proceeding. Second, a multi-agent architecture orchestrates inherently unreliable coding agents through automated validation and feedback, keeping long-running translation workflows on track with minimal human involvement. An ablation study confirms that feature reduction improves translation correctness compared to using multi-agent translation alone, with 6%--20% improvements in pass rates on validation test suites.
Bo Wang, Brandon Paulsen, Joey Dodds +3
National University of Singapore, Singapore · Amazon, USA
Translating C code into safe, idiomatic Rust is a longstanding software-engineering goal because it can eliminate entire classes of memory-safety vulnerabilities while preserving the functional behavior of legacy systems. Large language models (LLMs) have shown promise for this task but typically underperform when applied off-the-shelf, since general-purpose pretraining rarely emphasizes idiomatic Rust generation, cross-language semantic equivalence, or the ability to reason about and repair compiler/runtime feedback. In this report we describe a three-stage fine-tuning curriculum applied to Qwen3-27B that is designed to progressively specialize the model for the C-to-Rust (C2Rust) translation task: (1) continued pretraining on Rust-centric corpora to strengthen the model's prior over idiomatic Rust syntax and standard-library usage; (2) supervised fine-tuning (SFT) on the microsoft/Verus_Training_Data dataset to instill debugging and self-repair behavior over Rust code; and (3) task-specific SFT on paired C/Rust solutions derived from LeetCode problems to teach direct semantic translation. We evaluate the resulting model using the agentic, static-analysis-guided verification framework of SACTOR, which performs structure-aware, two-phase (unidiomatic to idiomatic) translation with foreign-function-interface (FFI)-based end-to-end (E2E) testing. We report success rate, idiomaticity (Clippy lint counts, unsafe-code fraction), and failure-mode analyses, and compare our fine-tuned model against baseline Qwen3-27B and other LLMs evaluated under the same framework.
Rust is increasingly adopted as a memory-safe successor to C, and transpilers such as \crust{} can migrate entire C projects while preserving their behavior. Preserving behavior, however, does not guarantee preserving performance. We study this gap on 20 real-world C projects and their \crust{} translations. On the eight projects used for analysis, the translated Rust is more than 3% slower than the original C on 12 of 19 operations, by up to 62.2%. By comparing execution-cost profiles, optimized LLVM IR, and compiler optimization remarks across each C--Rust pair, we trace these slowdowns to nine recurring performance issues, spanning residual runtime work, missed compiler optimizations, and C-style source patterns, and derive an optimization direction for each. We then present \ourtool{}, an LLM-based approach that encodes these issues as reusable optimization rules to recover the performance of translated Rust. \ourtool{} profiles each project to locate hot functions and matches them against rule-specific patterns. The LLM then checks each rule's rewrite preconditions against the project context before rewriting, and a rewrite is kept only if it passes both functional and performance validation. On 41 operations from twelve held-out projects, \ourtool{} preserves C outputs on all tested workloads and speeds up 40 operations over the \crust{} translations, 18 of which end up faster than the original C. It outperforms the general-purpose coding agent \codex{} on 31 of the 37 operations where both preserve C outputs, and outperforms its own variant without rule guidance on 34 of the 41 operations.
Zhiqiang Yuan, Chong Wang, Zhenhao Zhou +2
Department of Computer Science, Fudan University, China · Nanyang Technological University, Singapore