← All papers
First page of A Trust Ledger and an Execution Check for CPG-Based C-to-Lean 4 Autoformalization: Separating Declined from Silently Incorrect Translations

A Trust Ledger and an Execution Check for CPG-Based C-to-Lean 4 Autoformalization: Separating Declined from Silently Incorrect Translations

Ishan K Singavarapu, Manish Bhatt

cs.PL Sep 28, 2026 · v1 cs.CR
Translates C code (SQLite) via Joern CPG into terms of a fuel-indexed Lean 4 definitional interpreter, with Lean-checked specifications and execution checks.
Verifying large C codebases requires translating them into formally checkable semantics, but most autoformalization work reports a single aggregate success rate that conflates two different failure modes: code the translator declined to handle and code the translator translated incorrectly. We present a deterministic code-property-graph (CPG)-based exporter that translates C source into a small Lean 4 core semantics under a three-tier correctness discipline: hole-free, call-closed, and dynamic-hole-risk, that keeps these modes distinct. Applied to a re-export of the SQLite source tree (8{,}602 functions, over 1.5 million AST nodes), the exporter translates 5{,}222 functions (60.7%) hole-free, of which only 2{,}134 (24.8%) are call-closed, a $2.4\times$ gap a single rate would hide. Both figures are reported in a full per-construct trust ledger rather than a single score. Our main contribution is methodological: a protocol for separating constructs that are fundamentally unresolvable by whole-program static analysis (such as public API boundaries) from constructs that only look that way. For example, we retracted our own “impossible” classification of function-pointer/vtable dispatch after tracing a concrete counterexample in the target codebase. Separately, a search for “more holes closed” surfaced a latent silent-wrong-answer bug: a translation that succeeded with an incorrect result rather than declining, a failure mode we argue is more dangerous than any hole, and one a hole-count-only evaluation would never surface.

Autoformalization pipelines for code usually report a single coverage rate. That rate conflates constructs the translator declined to handle with constructs it translated incorrectly. Silently incorrect translations type-check and count as translated, so coverage cannot detect them.

A deterministic pipeline uses Joern's code property graph to export C source to JSON and then prints it as a term of a small, total, fuel-indexed Core interpreter written in Lean 4. Constructs that cannot be translated faithfully become holes labeled by cause. Coverage is reported in three tiers (hole-free, call-closed, dynamic-hole risk) with a per-cause trust ledger. Translated programs are executed and compared against compiled C to find silent miscompilations.

On SQLite (8,602 functions, 1.5M AST nodes), 60.7% of functions are hole-free but only 24.8% are call-closed, a 2.4x gap. Six documented cases show coverage and fidelity moving independently, including silent bugs in character literals, do-while loops and variadic signatures that no coverage number registered. A vtable-dispatch construct previously classified as impossible was also retracted after a counterexample was found.

MetricValue
Functions / AST nodes8,602 / 1,513,464
Hole-free5,222 (60.7%)
Call-closed2,134 (24.8%)
Residual holes / causes14,260 / 70
Dynamic-hole risk constructs216,730
SQLite export coverage tiers