Sound Borrow-Checking for Rust via Symbolic Semantics (Long Version)
Son Ho, Aymeric Fromherz, Jonathan Protzenko
TL;DR
This work addresses the challenge of giving a formal, sound semantic foundation for Rust’s borrow-checking by connecting LLBC, a borrow-centric core, to a traditional heap-based memory model via HLPL and the Pointer Language PL. It introduces LLBC#, a symbolic borrow-checker for LLBC, and proves that successful LLBC# executions imply safe LLBC (and hence PL) executions through a forward simulation, complemented by a backward simulation to PL for terminating cases. A novel join/collapse mechanism enables loop handling and composition of multiple control-flow branches, enabling loop-rich Rust programs to be analyzed within this framework. The results demonstrate a scalable, modular approach to proving semantic soundness and borrow-checking correctness, with implementations and case studies validating practical applicability and potential improvements to Rust’s borrow-checker.
Abstract
The Rust programming language continues to rise in popularity, and as such, warrants the close attention of the programming languages community. In this work, we present a new foundational contribution towards the theoretical understanding of Rust's semantics. We prove that LLBC, a high-level, borrow-centric model previously proposed for Rust's semantics and execution, is sound with regards to a low-level pointer-based language à la CompCert. Specifically, we prove the following: that LLBC is a correct view over a traditional model of execution; that LLBC's symbolic semantics are a correct abstraction of LLBC programs; and that LLBC's symbolic semantics act as a borrow-checker for LLBC, i.e. that symbolically-checked LLBC programs do not get stuck when executed on a heap-and-addresses model of execution. To prove these results, we introduce a new proof style that considerably simplifies our proofs of simulation, which relies on a notion of hybrid states. Equipped with this reasoning framework, we show that a new addition to LLBC's symbolic semantics, namely a join operation, preserves the abstraction and borrow-checking properties. This in turn allows us to add support for loops to the Aeneas framework; we show, using a series of examples and case studies, that this unlocks new expressive power for Aeneas.
