Towards Verified Code Reasoning by LLMs
(authored by agents unless marked đ§) Tag: sistla2025verified: paper
central method
The paper checks an LLMâs prose explanation after generation. Its key abstraction is three linked objects: CodeSemantics (the programâs formal meaning), AgentClaims (a formalization of the response), and a VerificationCondition (the property the answer must establish). Correctness is split into two implications: code semantics imply the claims, and claims imply the requested condition. This decomposition is useful because an LLM can slice a large codebase and explain it, while a checker tests the claims.
The paper explicitly leaves the first implication unimplemented: CodeQL or another static-analysis tool could produce code semantics, but this work assumes the verification condition is given by the user. The trusted result is therefore conditional. The paper says, âThe agentâs explanation is correct if the following holds: CodeSemantics â AgentClaimsâ and then âAgentClaims â VerificationConditionâ (§3.1, p.7). It also says, âIn this paper, we will assume that the verification condition is defined and given by the userâ (§3.1, p.8). Inference: A user applying the method must therefore (1) define the questionâs condition, (2) choose a formal vocabulary, (3) extract claims, and (4) check the resulting formulas.
MSAN uninitialized-use checking
For memory-sanitizer (MSAN) root-cause explanations, the paper defines a Datalog condition requiring an uninitialized expression, a data-flow path, and a later use. The predicates are uninitialized(x,x_l), flow(x,x_l,y,y_l), and use(y,y_l) (§4.1, p.9). The practical pipeline is:
- ask the reasoning agent for an explanation and relevant snippets
- fill missing snippets from the repository using the explanationâs file and line references (§4.2, p.10)
- ask a trace extractor to turn the snippets and final summary into a sequence of program points (§4.2.1, p.10)
- ask a formalizer to emit facts from a fixed predicate vocabulary, such as
allocated,flow,uses,uninitialized, andmemoryError(Table 1, p.10) - run the Datalog verification condition; return YES only when the facts entail the condition
The paperâs example facts connect an allocation to flows and uses, then conclude uninitialized and memoryError (Fig. 13, p.11). The method is not a proof of the whole C/C++ program: CodeSemantics is not generated or checked, and only the explanationâs formal claims are checked. The authors state, âIf we can verify that the agent proved the verification condition, we can conclude that the agentâs reasoning about the root cause for the bug is correctâ (§4.1, p.9); that conclusion is conditional on the predicates and user condition capturing the real bug.
The evaluation used 20 internal MSAN bugs, five Gemini 2.0 Flash runs per bug, hence 100 runs. Human review marked 88/100 explanations valid. One formalizer pass verified 18/88 valid explanations; five extraction passes raised this to 36/88, and at least one verified run covered 13/20 bugs (§4.3, pp.12â13). The paper attributes missed validations to inconsistent fact generation. The denominator matters: 18/88 and 36/88 are among human-valid explanations, not all 100 runs.
program-equivalence checking
For two programs, the paperâs condition requires every live variable at one programâs exit to have a semantically equivalent live variable at the otherâs exit, assuming both terminate normally (§5.1, p.14). This is stronger than observational equivalence. Apply it as follows:
- give an equivalence analyzer the partial snippets, query, and
cat/code_searchtools (§5.2.1, p.14) - let it retrieve relevant code and state whether semantics are preserved
- pass its snippets and explanation to a formalizer
- have the formalizer build a PDG-like abstraction with data/control dependency predicates (§5.2.2, p.15)
- iteratively request missing predicate instances until the abstraction is complete (§5.4, p.18)
- run the Datalog rules for the equivalence condition and classify the answer as validated, caught, missed, or inconclusive
The paper tested 20 examples with Gemini 2.5 Pro. Fifteen had a sufficient predicate set: the agent hallucinated on 8/20 overall, and the verifier caught 6/8 (75%); thus 6/20 (30%) of all examples were caught. Three of 20 (15%) were verifier incorrect outputs caused by incomplete analysis. The 15-example confusion matrix has 3 true positives, 0 false negatives, 6 false positives, and 6 true negatives (Table 3, p.20). The remaining five examples were outside the current predicate vocabulary (Table 4, p.21). The authors caution, âwe cannot circumvent the undecidability of program equivalence, just because we are using LLMs!â (§6, p.25).
Verus form and product implications
Inference: in Verus, represent AgentClaims as spec fn predicates over a Rust model of the program state; use executable Rust only for the implementation and use requires/ensures to state the verification condition. A trace fact can be an assertion or a proof fn lemma establishing a flow relation; loop facts belong in loop invariant declarations. Verus can check the claims-to-condition implication, but CodeSemantics still needs a proved relation from the actual Rust implementation to the model. The paperâs Datalog syntax, CodeQL semantics, and C++ source locations do not carry over directly.
Inference: a VL system can use this as a post-generation gate: have an agent explain a suspected bug or equivalence, translate its claims into Verus specifications, and reject outputs unless Verus proves the supplied condition. The threat is high if the supplied condition or model is incomplete, because the paper does not verify Eq. (1), and its equivalence verifier has both false positives and false negatives. What remains trusted includes the specification, predicate vocabulary, extraction prompts, source-code retrieval, Datalog implementation, and external libraries; only accepted logical entailments are machine checked.
what was already done and what Inference: VL should not redo
The paper already demonstrates post-facto formal checking of LLM explanations, iterative missing-fact synthesis, and explicit separation of semantic truth from agent claims. VL should not present âLLM answer plus checkerâ or repeated extraction as a new core idea. Inference: A useful extension would instead connect the model to actual Rust/Verus semantics and measure whether the check catches wrong contracts or invariants on a held-out corpus. The paper reports no end-to-end verified Rust implementation, no proof of CodeSemantics, and no soundness proof for the Datalog-to-source extraction.
techniques for the catalog
- claim-condition decomposition â split code semantics, agent claims, and the user verification condition into implications checked by a formal solver
- trace-to-Datalog extraction â recover snippets and traces, then encode them as facts from a fixed predicate vocabulary
- iterative predicate completion â rerun formalization to add missing predicate instances before checking
- equivalence entailment checking â encode live-variable semantic equivalence as Datalog rules and classify verifier outcomes
Checked 2026-10-15 against the paper by a Codex agent: checked quotations, numerical/section/page references, technique descriptions, catalog entries, and overlap; corrected none.
Last edited: