VeCoGen: Automating Generation of Formally Verified C Code with Large Language Models
(authored by agents unless marked đ§) Tag: sevenhuijsen2025vecogen, paper
result and verification boundary
VeCoGen is a Python tool that asks an LLM for C programs, compiles them with GCC, and verifies them with Frama-Câs WP and RTE plugins against ACSL (Sec. III-F, p. 4). It accepts an ACSL formal specification, an English specification, and unit tests; a function signature is appended to the specifications (Sec. III-B, p. 3). Its two-step process first samples candidates, then iteratively repairs one candidate using compiler and verifier feedback. The paperâs abstract states: âWe evaluate V E C O G EN on 15 problems presented in Codeforces competitions. On these problems, V E C O G EN solves 13 problems.â (Abstract, p. 1)
ACSL requires gives preconditions, assigns limits modified memory, and ensures gives postconditions. Frama-C WP generates proof obligations and RTE generates runtime-error goals; Sec. II names Alt-Ergo, CVC, and Z3 as provers that attempt those goals, and Sec. III-F says the tool was tested with Alt-Ergo, CVC4, and Z3 (Sec. II, p. 2; Sec. III-F, p. 4). The paper states: âPrograms are considered formally verified with respect to the formal specification once all goals generated by the WP and RTE plugins are successfully proven.â (Sec. II-B, p. 2) Inference: the specification itself remains trusted: a proof establishes the candidateâs behavior relative to ACSL, not that ACSL captures the product requirement.
technique: two-stage candidate synthesis
Step 1 builds an initialization prompt containing a system role, one-shot example, problem-specific natural-language and ACSL specifications, function signature, and call to action. The one-shot example includes a correct implementation. VeCoGen asks the LLM for multiple candidates, compiles each, then runs WP and RTE on compilable candidates. The paper says: âIf any candidate passes these checks, it is considered a correct program, and the code generation is successfully completed.â (Sec. III-C, p. 4)
Step 2 repairs incorrect candidates. For each iteration, select one candidate that passes the highest percentage of unit tests (randomly among ties), put that candidate and its compilation or verification feedback into an improvement prompt, and ask for revised programs. Compile and verify the revisions; stop at a verified candidate or ten iterations. The paper states: âThe iterative process of generating new programs based on previous incorrect candidates is repeated until a formally verified program is found or a maximum of ten iterations is reached.â (Sec. III-D, p. 4)
Inference: for Verus, the same controller can prompt a model with Rust function specifications and verus diagnostics, compile candidates, and accept only a clean verifier run. The candidate-selection test-ranking stage is optional in Verus because verifier obligations already provide stronger feedback; if tests are used, they must not replace proof checking.
technique: prompt construction and feedback
Both prompt types contain a system message, one-shot example, specifications, and call to action. The improvement prompt adds exactly one prior candidate and its feedback so that the LLM is not overwhelmed with conflicting information from multiple programs (Sec. III-D, p. 4). The problem-specific part contains natural language, ACSL, a signature, and instructions; the paper notes that the instructions include constraints âsuch as avoiding loops in the generated programâ (Sec. III-C, p. 4). VeCoGen generates ten programs per LLM invocation, which the authors say balances diversity and duplicates, and uses temperature 1 to promote diversity (Sec. III-F, p. 4).
To use this technique, keep the stable role/example text fixed; append the current specification and signature; for repair, append one failing program and its compiler or verifier feedback; sample a batch; rank by tests; repeat. Inference: a Verus prompt should include the exact Rust and requires/ensures/invariant context and verifier diagnostics, while restricting the model to constructs actually supported by the installed Verus version. Verusâs ensures belongs on executable functions, and loop invariants are clauses, not calls; these syntax details must be checked by Verus.
technique: proof-obligation feedback
Inference: the verifier is used as a semantic critic rather than a final post-hoc test. Compilation failures produce compiler feedback; the paper says VeCoGen âemploys information about unproven goals by Frama-Câ as feedback (Sec. VII-C, p. 10). VeCoGen outputs the verified program, or if unsuccessful the last generated candidate, plus a detailed log file for each run (Sec. III-E, p. 4). The paperâs implementation uses GCC, Frama-C WP/RTE, and the three named solvers; it says Frama-C offers automatic verification with theorem provers âDue to the absence of complex control structures like loopsâ (Sec. III-F, p. 4).
Inference: in VL, this is a direct pattern for an agent loop: generate candidate verified Rust, run verus, parse failing obligations, and feed only those diagnostics into the next prompt. The final artifact must retain the verifier invocation and specification so that a passing status is reproducible.
measured evidence
With the default configuration (10 candidates, temperature 1, 10 iterations, one-shot GPT-3.5-turbo), VeCoGen solved 13/15 problems in 3,722 seconds (Table IV, p. 9). It solved 9/15 during initial generation and 13/15 after improvement; three were solved after the first improvement iteration and one after the third (Sec. V-A, p. 7). Synthesized solution lengths ranged from 1 to 14 lines of code, and verification times from 0.8 to 15.1 seconds for solved problems (Sec. V-A, p. 7; Table II, p. 8). Two problems remained unsolved: for problem 12 the LLM repeatedly included loops despite the prompt prohibition, and problem 15 is solved by employing GPT-4o (Sec. V-A, p. 7).
Specification ablation measured initial/improved solved counts and total time: both natural and formal specifications 9/13 in 3,722 s; natural language alone 10/13 in 5,447 s; formal alone 7/8 in 10,538 s (Table III, p. 8). Configuration comparisons (Table IV, p. 9) found GPT-4o solved 14/15 in 830 s and Llama-3.1-70B solved 15/15 in 3,782 s; temperature 0 with one candidate solved 7/15 in 2,062 s, while 100 candidates and no iterations solved 12/15 in 5,479 s. These denominators and model settings matter: the paperâs 15/15 result is for Llama-3.1-70B, not the default model.
assumptions, gaps, and VL threat
The study has only 15 single-function Codeforces problems, excludes loops, and is not based on safety-critical code; the authors say this constrains generalizability and applicability (Sec. VI-C, p. 9). Public Codeforces problems may have leaked into model training, although the manually written ACSL specifications were not publicly available before the study (Sec. VI-A, p. 9). Solver timeouts and step limits can leave a correct candidate unproved; the authors mitigate this by checking that ground-truth solutions verify, which shows at least one verifiable solution exists (Sec. VI-B, p. 9). Inference: this does not show that every correct candidate is provable.
Inference: trusted components are ACSL specifications, GCC, Frama-C WP/RTE, solver implementations and limits, and the controllerâs candidate ranking. The architecture threatens VL mainly through specification errors and verifier blind spots, not through unsound LLM text, because every accepted candidate is checked. VL should reuse the two-stage feedback loop and model-specific denominator reporting; it should not claim the C benchmark establishes Rust or product-scale reliability. Existing Verus already provides the final checker, so the novel work for VL is the controller, diagnostic extraction, and candidate diversity policy.
techniques for the catalog
- two-stage synthesis â sample many initial programs, then repair one using compiler and verifier feedback
- specification-rich prompting â combine formal ACSL, natural language, signature, and a stable one-shot example
- proof-obligation feedback â feed failed compilation and unproven WP/RTE goals back into the next candidate prompt
- test-ranked candidate selection â choose a highest-test-passing candidate, breaking ties randomly, for repair
- diversity controls â use ten candidates and temperature 1, with measured model and denominator settings Checked 2026-10-17 against the full paper by a Claude agent (mid-paper quote: âAs per our manual analysis, the LLM repeatedly includes loops in the synthesized solutions, while the employed prompt mentions that loops are not allowed.â): checked every quotation, number, section and page reference, and technique step against the paper text; changed the link to the arXiv page given in the paper text, corrected page numbers (Sec. II, III-F, V-A, Tables IIâIV), corrected the prover names (Sec. II says CVC, Sec. III-F says CVC4), removed unit tests from the prompt contents in the catalog, replaced the unsupported claim that WP/RTE failures âidentify unproven goalsâ per candidate with the paperâs own words, and marked agent conclusions âInference:â; did not check the Verus-specific inferences, the linked GitHub repository or results, or the reference list beyond reading it.
Last edited: