Fact-checked by Grok 2 weeks ago

Hoare logic

Hoare logic is a for reasoning about the correctness of computer programs using a set of axioms and inference rules to derive logical assertions about program behavior. Introduced by C. A. R. Hoare in 1969, it provides an axiomatic approach to program , allowing programmers to prove that a program satisfies its specification by establishing relationships between preconditions and postconditions. The core construct of Hoare logic is the Hoare triple {P} S {Q}, where P and Q are logical assertions (predicates) describing the state before and after execution of statement S, respectively; this denotes that if P holds upon initiation of S, then Q will hold upon its completion, assuming S terminates. The system includes a basic for statements, such as {P [e/x]} x := e {P}, which states that substituting expression e for variable x in P yields the postcondition after the assignment. Inference rules enable composition of triples, including the sequencing rule {P} S₁ {R} and {R} S₂ {Q} implying {P} S₁ ; S₂ {Q}, the conditional rule for if-statements, and the while-rule for loops based on invariants. Initially focused on partial correctness—verifying that if the program terminates, the postcondition holds—Hoare logic was extended within its first decade to total correctness, incorporating termination arguments via variant functions or strengthened loop rules. These extensions addressed limitations in handling recursive procedures, local variables, and parameters, with and results established for while-programs and beyond. Hoare logic's significance lies in its foundational role in deductive program verification, influencing the design of programming languages like Pascal and serving as a basis for mechanized tools that automate proof generation. Modern applications include verification systems such as , which uses Hoare-style preconditions, postconditions, and loop invariants to check functional correctness in a language with imperative and functional elements, and , a Java verifier employing Hoare logic for symbolic execution and automated theorem proving of partial and total correctness.

Introduction

Overview and Purpose

Hoare logic is a for reasoning about the correctness of imperative by specifying that must hold before a 's execution and postconditions that are guaranteed to hold afterward, assuming the precondition is satisfied. This approach provides a deductive framework based on first-order predicate logic with , where program states are represented as assignments of values to variables, enabling rigorous proofs about behavioral properties. The primary purpose of Hoare logic is to facilitate of correctness, distinguishing between partial correctness—which ensures that if the terminates, the postcondition holds—and total correctness, which additionally guarantees termination under the precondition. By axiomatizing constructs and providing inference rules, it allows programmers to construct machine-checkable proofs that a meets its specification without relying on or testing. Proposed by C. A. R. Hoare in 1969, this system extends Robert W. Floyd's 1967 method for assigning meanings to programs, shifting the focus from graphical representations to textual imperative languages. At its core, Hoare logic employs triples of the form {P} S {Q} to denote that statement S preserves assertion Q from P, though detailed syntax is addressed elsewhere.

Historical Development

The development of Hoare logic traces its roots to early efforts in formal verification during the 1960s. A key precursor was Robert W. Floyd's 1967 paper, "Assigning Meanings to ," which introduced a for verifying the correctness of flowchart-based programs using inductive assertions placed at program points to establish logical relationships between states. Floyd's approach provided a foundational technique for reasoning about program behavior without executing the code, influencing subsequent axiomatic methods by emphasizing assertions to bridge pre- and post-execution conditions. The formal establishment of Hoare logic occurred in 1969 with C. A. R. Hoare's seminal paper, "An Axiomatic Basis for ," published in Communications of the ACM. In this work, Hoare introduced Hoare triples of the form {P} S {Q}, where P is a , S a program statement, and Q a postcondition, along with axioms and inference rules to prove partial correctness. A pivotal contribution was the while-rule, which addressed reasoning about iterative constructs like loops by incorporating loop invariants to handle non-terminating behavior. This axiomatic framework shifted program toward a proof-based discipline akin to , enabling systematic deduction of program properties. In the 1970s, early refinements to Hoare logic emerged alongside advances in , with significant contributions from and others. Dijkstra's 1976 book, A Discipline of Programming, integrated weakest semantics to strengthen techniques, building on Hoare's foundations to support more rigorous program derivation. Initially focused on partial correctness—ensuring that if the program terminates, the postcondition holds—Hoare logic saw extensions to total correctness in the 1970s, incorporating termination guarantees through variant functions and modified rules like the WHILE II rule. These developments solidified Hoare logic as a cornerstone of , influencing broader efforts in software reliability.

Core Concepts

Hoare Triples

Hoare triples provide the foundational notation for specifying and reasoning about the correctness of imperative in Hoare logic. The notation, introduced by C. A. R. Hoare, takes the form P \{ S \} Q, where P is an assertion serving as the that must hold in the initial state before executing the program S, and Q is the postcondition that is guaranteed to hold in the final state upon completion of S. The semantics of a Hoare triple P \{ S \} Q assert that if the P is true before the initiation of S, and if S executes to completion without error, then the postcondition Q will be true afterward; this formulation corresponds to partial correctness, focusing on the relationship between initial and final rather than guaranteeing termination. In this framework, programs operate within a defined by the values of program variables, and assertions like P and Q are predicates—logical expressions that evaluate to true or false over these , capturing properties such as variable equalities or inequalities. For illustration, consider the simple assignment where the variable x is incremented from an initial value of zero: \{ x = 0 \} \, x := x + 1 \, \{ x = 1 \}. Here, the ensures x starts at zero, and the postcondition verifies that it ends at one, assuming the assignment executes successfully. This notation differs from the earlier approach by , which attached predicates directly to the edges of program flowcharts to verify paths, whereas Hoare's triples are more directly tied to the syntax of imperative statements in .

Assertions and Semantics

In Hoare logic, assertions are formal expressions that describe properties of program s, typically formulated in logic over the program's variables. A is a valuation assigning values to these variables, and an assertion predicates the set of states satisfying it; for instance, the assertion x > 0 \land y = 5 holds in states where the variable x exceeds zero and y equals five. This language enables precise specifications of preconditions and postconditions in Hoare triples, capturing invariant properties throughout program execution. The semantics of program execution in Hoare logic interprets commands as transformations on states, where a command C maps initial states to final states upon termination. Central to this is the weakest precondition semantics, introduced by Dijkstra, which defines wp(C, Q) as the strongest assertion P such that if the program starts in a state satisfying P, then upon terminating, it reaches a state satisfying the postcondition Q. This predicate transformer formalizes the backward reasoning essential to verifying triples \{P\} C \{Q\}, ensuring P implies wp(C, Q). Hoare logic's axiomatic approach provides operational reasoning about program behavior through , contrasting with that model programs as mathematical functions from inputs to outputs or domains. While denotational methods emphasize compositional function definitions, Hoare logic focuses on step-by-step state transitions and proof rules for partial or total correctness. A key property of Hoare logic is its soundness: any provable using the axioms and rules is semantically valid with respect to the execution model. Relative holds when the assertion language is sufficiently expressive, meaning that if a is semantically true, it is provable assuming an oracle for the underlying ; this result, due to , relies on the ability to express loop invariants and other auxiliaries. For practical verification, assertions are often restricted to a decidable fragment of to avoid undecidability issues in checking validity, though full expressiveness is needed for relative completeness. This trade-off ensures automated tools can handle common cases while acknowledging theoretical limits.

Partial versus Total Correctness

In Hoare logic, partial correctness for a command C is specified by a Hoare triple \{P\} C \{Q\}, which asserts that if the program starts in a state satisfying the precondition P and C terminates, then the final state will satisfy the postcondition Q. This notion, introduced in the foundational work on axiomatic semantics, provides no guarantee that C will terminate, focusing solely on the behavioral correctness assuming termination occurs. Total correctness strengthens this by requiring that whenever the precondition P holds, the command C not only terminates but also reaches a state satisfying Q. Thus, total correctness encompasses partial correctness plus a proof of termination, often necessitating auxiliary structures like variant functions to demonstrate progress toward termination in loops. While the same notation \{P\} C \{Q\} is commonly used for both, variants such as [P] C [Q] or boldfaced triples distinguish total correctness in some formulations to emphasize the added termination requirement. Partial correctness is particularly suited to programs where termination is either assumed or handled separately, as it simplifies proofs by avoiding the complexities of non-termination analysis. In contrast, total correctness demands more rigorous , including loop invariants combined with termination arguments, making it essential for fully verified systems but challenging due to the undecidability of termination in Turing-complete languages. The while rules in Hoare logic differ accordingly, with the partial version relying on invariants alone and the total version incorporating a decreasing .

Axioms and Inference Rules

Assignment Axiom

The assignment axiom forms the basis for reasoning about assignment statements in Hoare logic, allowing verification of how updates affect program assertions. It is expressed by the schema \{ Q[x / E] \} \ x := E \ \{ Q \}, where x is a , E is an expression, Q is the postcondition assertion, and Q[x / E] denotes the result of replacing all free occurrences of x in Q with E (known as backward ). This rule operates backward from the postcondition: to ensure Q holds after the assignment, the precondition must be Q with the assigned value E substituted for x, accounting for the state change caused by the update. The axiom handles arbitrary expressions E, assuming their evaluation terminates without side effects or errors. It is foundational for reasoning about variable updates, enabling the construction of preconditions for more complex statements built upon assignments. The assignment axiom derives from the weakest precondition semantics, where the weakest precondition for an assignment is defined as \mathrm{wp}(x := E, Q) = Q[x / E]. For example, consider verifying the triple \{ y = x + 1 \} \ x := x + 1 \ \{ y = x \}. Here, the postcondition Q is y = x, so the precondition is obtained by substituting E = x + 1 for x in Q, yielding y = (x + 1), which matches the given precondition.

Skip Axiom

The skip axiom in Hoare logic addresses the semantics of the statement, a command that performs no action and alters neither the program state nor the . Formally, the is given by \{P\} \skip \{P\}, where P is any valid assertion over the program state; this asserts that if the P is true immediately before executing , then P remains true as the postcondition after its execution. This captures the essential property that induces no change in the state, thereby ensuring the implies the postcondition identically without requiring any or evaluation. As a result, the holds vacuously for false preconditions and serves as a foundational truth for any true P, directly following from the where immediately terminates in the same state. The axiom plays a crucial role as the base case in Hoare logic's proof system, particularly for sequential composition, where it enables the of correctness for statements by treating skip as the in program sequencing. It also underpins proofs for empty or inactive program fragments, establishing that such terminating code preserves all relevant properties without introducing errors or side effects. In the framework of partial correctness, this axiom applies straightforwardly, as skip always terminates and thus avoids any issues inherent to loops or other constructs.

Composition Rule

The composition rule in Hoare logic, introduced as a key inference rule for sequential program verification, permits deriving a Hoare triple for the concatenation of two commands from triples for each command individually. The rule's schema is given by \frac{ \{P\} \, C_1 \, \{R\} \quad \{R\} \, C_2 \, \{Q\} }{ \{P\} \, C_1; C_2 \, \{Q\} } where P and Q are the overall precondition and postcondition, respectively, C_1 and C_2 are the commands in sequence, and R serves as an intermediate assertion linking the postcondition of C_1 to the precondition of C_2. This formulation ensures that if C_1 transforms states satisfying P into those satisfying R, and C_2 transforms states satisfying R into those satisfying Q, then the composed command C_1; C_2 transforms states satisfying P into those satisfying Q, provided the program terminates. The intermediate assertion R can be chosen flexibly, but a common and effective selection is the weakest precondition of C_2 with respect to Q, denoted \mathrm{wp}(C_2, Q), which yields the least restrictive condition on the output of C_1 while guaranteeing the desired postcondition. This choice facilitates backward reasoning from the overall postcondition and strengthens the verification of the prefix command. The composition rule supports modular verification by decomposing proofs along the sequential structure of programs, allowing independent analysis of subcomponents connected via intermediate assertions. It is sound with respect to partial correctness semantics, meaning that any triple derived using the rule holds whenever the program terminates in a state reachable from the precondition.

Conditional Rule

The conditional rule in Hoare logic governs the of statements, enabling the proof of correctness for programs that branch based on a B. For the case with the same postcondition Q for both branches, the is: \frac{ \{P \land B\} \, C_1 \, \{Q\} \quad \{P \land \lnot B\} \, C_2 \, \{Q\} }{ \{P\} \, \text{if } B \, \text{then } \, C_1 \, \text{else } \, C_2 \, \{Q\} } This rule is derived through case analysis on the value of B and relies on the consequence rule. For differing postconditions Q1 and Q2 on each branch (assuming the branches do not modify variables in B), if {P \land B} C_1 {Q_1} and {P \land \lnot B} C_2 {Q_2}, then {P} if B then C_1 else C_2 {(B \land Q_1) \lor (\lnot B \land Q_2)}. This generalized form arises by applying the consequence rule to adjust postconditions and combine them to reflect the branch taken. The rule handles partial correctness, assuming that if the relevant branch is taken (i.e., if P \land B or P \land \lnot B holds), then the corresponding command C_1 or C_2 will terminate, after which the postcondition is satisfied. Assertions express the boolean condition B and the postconditions, facilitating case analysis for branching behavior in programs.

Consequence Rule

The consequence rule in Hoare logic is a fundamental inference rule that enables the adaptation of Hoare triples to alternative preconditions and postconditions based on logical implications. Formally, it states that if P' \implies P, \{P\} \, C \, \{Q\}, and Q \implies Q', then \{P'\} \, C \, \{Q'\}. This rule, also expressed in equivalent forms such as strengthening the precondition or weakening the postcondition separately, supports monotonic reasoning by allowing stronger preconditions P' (which imply the original P) or weaker postconditions Q' (implied by the original Q) while preserving the validity of the triple. The rule plays a crucial role in connecting formally provable Hoare triples to actual program specifications, facilitating by permitting the use of more general or context-specific assertions in proofs. It is essential for practical verification, as it allows proofs to align with high-level requirements without being restricted to the exact assertions derived from axioms. When combined with the other axioms and rules of Hoare logic, the consequence rule contributes to the of the system, ensuring that any valid assertion about a structured can be formally derived. It applies uniformly to both partial correctness (where non-termination is permitted) and total correctness (which additionally guarantees termination), with the underlying implication relations adjusted accordingly for the respective semantics.

While Rule for Partial Correctness

The while rule for partial correctness in Hoare logic addresses the verification of loop constructs, ensuring that if the program terminates, the postcondition holds given the precondition. Formally, the rule states: if \{I \land B\} \, C \, \{I\}, then \{I\} \, \mathbf{while} \, B \, \mathbf{do} \, C \, \{I \land \lnot B\}, where I is a , B is the loop condition, and C is the loop body. This rule relies on the loop invariant I, which must hold immediately before the loop begins and immediately after each execution of the body C whenever B is true. Upon loop exit, when \lnot B becomes true, I continues to hold, establishing the desired postcondition I \land \lnot B. The invariant thus captures properties preserved across iterations, bridging the precondition and postcondition without addressing loop termination. To apply the rule, an appropriate invariant I must be identified such that it is preserved by the loop body under the condition B—that is, the weakest precondition of C with respect to I implies I \land B—and such that I \land \lnot B implies the overall postcondition of the enclosing program. This preservation is typically verified using the assignment axiom and other inference rules, such as the conditional rule for handling the test B. Notably, the while rule establishes only partial correctness, meaning it guarantees the postcondition if the loop terminates but provides no assurance that termination occurs; separate arguments are required for termination in total correctness settings.

While Rule for Total Correctness

The while rule for total correctness in Hoare logic establishes both the preservation of the postcondition and the guaranteed termination of a while loop, extending the framework beyond partial correctness by incorporating a termination proof. This rule relies on a loop invariant I that holds before and after each iteration, combined with a variant function t that measures progress toward loop exit. The rule schema is given by: If \{ I \land B \land t = z \} \, C \, \{ I \land t < z \} and I \land B \implies t \geq 0, then \{ I \land t \geq 0 \} \, \text{while } B \, \text{do } \, C \, \{ I \land \lnot B \land t \geq 0 \}, where I is the loop invariant assertion, B is the loop condition, C is the loop body, t is the variant function (an expression yielding a value in a well-founded domain, such as the non-negative integers under the standard ordering), and z is a fresh integer variable capturing the initial value of t. The variant function t ensures termination by strictly decreasing on every iteration where B holds: the premise \{ I \land B \land t = z \} \, C \, \{ I \land t < z \} certifies that executing C preserves I and reduces t below its starting value z for the iteration, while the implication I \land B \implies t \geq 0 bounds t below by zero initially. Since the non-negative integers admit no infinite descending chain under <, repeated strict decreases imply the loop executes only finitely many times before \lnot B holds, at which point I \land \lnot B \land t \geq 0 is established (as decreases preserve non-negativity). The requirement that t decreases by at least 1 in the integer case follows from the strict inequality and the discrete nature of the domain; more generally, t must map to any well-founded set to prevent infinite descent. This rule, which demands both invariant preservation and a decreasing variant, was introduced in the 1970s by to unify proofs of correctness and halting for programs where termination can be established axiomatically, though it cannot resolve all cases due to the undecidability of the .

Examples and Applications

Verifying Simple Statements

Hoare logic enables the verification of simple, non-looping programs through the application of basic axioms and inference rules, such as the assignment axiom and rules for composition and conditionals, typically via backward reasoning from the postcondition. This approach substitutes expressions into assertions to derive required preconditions, allowing modular construction of proofs for straight-line code without the need for loop invariants. A representative example involves verifying an assignment chain. Consider the Hoare triple \{x = 0\} \, x := 1; \, y := x \, \{y = 1\}, assuming integer variables. To prove this, apply backward reasoning using the composition rule, which states that if \{P\} \, S_1 \, \{Q\} and \{Q\} \, S_2 \, \{R\}, then \{P\} \, S_1; S_2 \, \{R\}. Start with the postcondition R = y = 1 for the second statement S_2 = y := x. By the assignment axiom \{Q[e/v]\} \, v := e \, \{Q\}, substitute e = x for v = y in Q = y = 1, yielding the intermediate assertion Q = x = 1. Thus, \{x = 1\} \, y := x \, \{y = 1\}. Next, for the first statement S_1 = x := 1 with postcondition x = 1, apply the assignment axiom with e = 1 for v = x, yielding the precondition $1 = 1, which is \top (true). Thus, \{\top\} \, x := 1 \, \{x = 1\}. By the consequence rule, since x = 0 \implies \top, it follows that \{x = 0\} \, x := 1 \, \{x = 1\}. Composing the two triples gives the desired result, demonstrating how substitution and implication connect the initial precondition to the final postcondition. Another example verifies a simple conditional statement that preserves a property. Consider \{x \geq 0\} \, \text{if } x > 0 \, \text{then } x := x - 1 \, \text{else } \text{[skip](/page/Skip)} \, \{x \geq 0\}, again assuming integers. The conditional rule states that if \{P \land B\} \, S_1 \, \{R\} and \{P \land \lnot B\} \, S_2 \, \{R\}, then \{P\} \, \text{if } B \, \text{then } S_1 \, \text{else } S_2 \, \{R\}. Here, P = x \geq 0, B = x > 0, S_1 = x := x - 1, S_2 = \text{[skip](/page/Skip)}, and R = x \geq 0. For the then-branch, P \land B = x > 0. By the assignment axiom applied to S_1, the precondition is (x - 1) \geq 0, or x \geq 1. Since x > 0 implies x \geq 1 for integers, the consequence rule yields \{x > 0\} \, x := x - 1 \, \{x \geq 0\}. For the else-branch, P \land \lnot B = x = 0. By the skip axiom \{R\} \, \text{skip} \, \{R\}, we have \{x \geq 0\} \, \text{skip} \, \{x \geq 0\}, and since x = 0 \implies x \geq 0, the consequence rule applies. The conditional rule then combines these to establish the triple, illustrating modular verification where each branch independently ensures the postcondition under the respective guards.

Proving Loop Correctness

Proving the correctness of loops in Hoare logic relies on the while rule for partial correctness, which requires identifying a —a that holds before the , after each , and upon termination when the condition is false. This , combined with the guard, ensures the postcondition is achieved if the terminates. For total correctness, an additional variant—a non-negative expression that strictly decreases with each and is bounded below—is introduced to guarantee termination. A classic example is verifying the loop that increments a x from 0 to 10: \{x = 0\} \text{while } x < 10 \text{ do } x := x + 1 \{x = 10\}. An appropriate invariant is I: 0 \leq x \leq 10. To prove partial correctness, first establish initialization: the precondition x = 0 implies I. Next, show preservation: assuming I \land x < 10, the body x := x + 1 maintains I, since substituting the post-state into I yields $0 \leq x + 1 \leq 10, which holds under the assumption $0 \leq x < 10. Finally, upon exit, I \land \lnot (x < 10) simplifies to $0 \leq x \leq 10 \land x \geq 10, implying x = 10. For total correctness of the same loop, introduce a variant t = 10 - x, which is non-negative under the invariant and strictly decreases by 1 each iteration (since x increases by 1 while x < 10). As t is bounded below by 0, the loop must terminate after finitely many steps, at most 10 iterations. Common pitfalls in selecting invariants include choosing one that fails preservation (e.g., x \leq 9 for the above loop, which does not hold after x := x + 1 when x = 9) or initialization (e.g., omitting the lower bound $0 \leq x). A heuristic to avoid this is to weaken the postcondition by relating it to the loop counter, ensuring it holds initially and is preserved by the body. Hoare logic with such invariants has been applied to verify algorithms like factorial computation, where the invariant y \times x! = n! \land 0 \leq x \leq n (with precondition n \geq 0 \land y = 1 \land x = n) proves \{n \geq 0\} \text{while } x > 0 \text{ do } (y := y \times x; x := x - 1) \{y = n!\}, using variant x for termination.

Use in Formal Verification

Hoare logic serves as a foundational framework for in , enabling the rigorous proof of program correctness through annotations and . In practice, developers annotate with preconditions, postconditions, and loop invariants expressed as Hoare triples, which are then processed by verification tools to generate proof obligations. These obligations are discharged using automated provers or SMT solvers, ensuring that the code satisfies its specified behavior without runtime errors or violations of safety properties. This deductive approach contrasts with testing by providing exhaustive guarantees for all possible inputs, making it particularly valuable for safety-critical systems where partial checks are insufficient. In embedded systems, Hoare logic is applied to verify safety properties in resource-constrained environments, such as software, where failures can have catastrophic consequences. For instance, tools based on Hoare logic have been used to prove the correctness of control algorithms in modules, ensuring compliance with timing and functional requirements by deriving weakest preconditions from annotated . A notable example involves the of rotor threshold checks in unmanned aerial vehicles, where , a verifier rooted in Hoare logic, confirms absence of overflows and adherence to safety invariants using Z3 as the backend solver. Such applications demonstrate Hoare logic's role in embedding mathematical proofs directly into development workflows for high-assurance systems. Key tools integrating Hoare logic include , Why3, and ESC/Java, each facilitating automated for imperative languages. supports modular of programs in a language close to C#, allowing users to specify contracts that are checked via intermediate language and solving, with applications in verifying concurrent data structures and system kernels. Why3 acts as a platform for deductive , translating annotated WhyML code into conditions for multiple solvers, and has been employed to prove of algorithms like binary heaps. ESC/Java, an extended static checker for , employs Hoare-style annotations to detect common errors such as dereferences, generating conditions via weakest preconditions that are solved interactively or automatically. These tools streamline the annotation and proof process, reducing manual effort while scaling to industrial bases. Hoare logic influences certification standards in , such as , through its integration into the formal methods supplement DO-333, which credits mathematically rigorous techniques for achieving objectives like and error detection. In this context, Hoare-based deductive proofs contribute to levels A and B software assurance by formalizing requirements and demonstrating equivalence between implementations and specifications. Beyond traditional domains, Hoare logic extends to smart contracts, where it verifies functional correctness and security properties, such as in Ethereum scripts, using theorem provers like Isabelle/HOL to ensure post-execution states match intended outcomes without reentrancy vulnerabilities. For enhanced scalability, modern approaches combine Hoare logic with to handle larger spaces while retaining deductive precision. This hybrid method uses Hoare triples for modular abstraction of program behaviors, followed by model checkers to explore finite- models of the abstracted system, verifying properties like liveness and in hardware-software co-designs such as secure system-on-chips. Such mitigates the explosion problem inherent in pure model checking, enabling verification of complex embedded components with bounded resources.

Handling Procedures and Jumps

Hoare logic's original formulation focused on simple imperative statements, but early extensions in the 1970s addressed procedures (subroutines) to support modular program verification. In a foundational paper, C. A. R. Hoare presented an for procedures with parameters, distinguishing between changeable formal parameters (assignable within the procedure) and read-only ones (constants). This approach specifies procedures via pre- and postconditions, enabling compositional reasoning where the caller's assertions are preserved across invocations. The core rule for procedure calls, known as the call axiom or rule of invocation, states that if a procedure p(\tilde{y}) : (X) proc Q has precondition P and postcondition Q (with \tilde{y} as changeable formals and X as read-only), and the call uses actuals a for \tilde{y} and expressions e for X, then \{P\} call p(a) : (e) \{R\} holds provided P[Q/\tilde{y}, e/X] implies R after substitution and parameter matching (formals = actuals). This rule leverages the composition rule briefly, substituting the procedure body into the call site while adjusting assertions for parameter passing. Handling parameters requires rules for substitution to avoid aliasing issues, such as ensuring actual variables are distinct and non-overlapping with expressions. Challenges in verifying procedures include proving correctness for , which demands inductive arguments or fixed-point semantics to establish invariants across interdependent calls, and managing parameter mechanisms like call-by-value versus call-by-reference to prevent unintended side effects. These issues were addressed in 1970s extensions, notably by Ralph L. London et al., who developed proof rules for structured languages like , emphasizing modular verification without arbitrary . A simple example is a factorial procedure: declare proc fact(r) : (n) proc with precondition n \geq 0 and postcondition r = n!, implemented as if n = 0 then r := 1 else begin temp := [n - 1](/page/N+1); call fact(r) : (temp); r := n \times r end. Verification proceeds by assuming the recursive call's postcondition and proving the base case and inductive step via adaptation rules. Extensions for jumps and gotos handle unstructured , which disrupts sequential composition. In the , rules for jumps were incorporated in verified software production, using auxiliary () variables to track states across non-local transfers without altering semantics. A common approach employs triples for labels: for a label L, the \{P\} goto L \{P_L\} holds where P_L is the assertion at L, often strengthened with auxiliary variables to relate pre-jump and post-jump states (e.g., \{R\} goto L \{\bot\} to ensure R at the target). These rules, refined by Clint and Hoare, use proof outlines where jumps merge control paths via entailment: if \{P\} s_1 \{R\} and \{R\} s_2 \{Q\}, then \{P\} begin s_1; L: s_2 end \{Q\} for jumps to L. Auxiliary variables, such as a , preserve invariants during jumps, enabling of loops or conditionals with early exits. Challenges include renaming nested labels to avoid ambiguity and ensuring termination in the presence of arbitrary gotos, which these extensions mitigate by favoring structured programs over .

Concurrency and Separation Logic

Hoare logic's extension to concurrent programs addresses the challenges of shared state and interference between parallel processes. One foundational approach is the rely-guarantee method, introduced by Cliff Jones in 1983, which augments Hoare triples to account for mutual assumptions about interference. In this framework, a concurrent command pair executes under preconditions P_1 and P_2, with command C_1 relying on the guarantee from C_2 (and vice versa) to ensure postconditions Q_1 and Q_2. The rule takes the form \{P_1, R_1, G_1\} C_1 \{Q_1, R_2, G_2\} \parallel \{P_2, R_2, G_2\} C_2 \{Q_2, R_1, G_1\}, where R_i and G_i specify the expected changes (rely) and promised behaviors () to the other thread, enabling compositional reasoning about shared variables. This handles shared state assumptions by framing interference as predictable relations between pre- and post-states, avoiding global invariants for scalability in multithreaded . A significant advancement integrates Hoare logic with , developed by John Reynolds in the early 2000s and extended to concurrency by Peter O'Hearn and collaborators. extends assertions with a separating P * Q, meaning the heap is partitioned into disjoint parts satisfying P and Q separately, which directly supports local reasoning about mutable data structures. In the concurrent setting, Concurrent Separation Logic (CSL) combines this with rely-guarantee principles, allowing threads to own disjoint heap portions while sharing resources via protocols like locks. This addresses pointers and aliases in multithreaded code by enforcing ownership transfer and preventing races through atomicity assumptions, such as treating critical sections as instantaneous heap manipulations. For instance, the parallel composition rule in CSL is \{P_1 * P_2\} C_1 \parallel C_2 \{Q_1 * Q_2\} when no sharing occurs, or extended with shared invariants for blocks. These developments, pioneered by O'Hearn, Reynolds, and others in the 2000s, have influenced practical systems, including the ownership model in the Rust programming language, which draws from separation logic to enforce thread safety at compile time without a garbage collector. A representative example is verifying a parallel counter increment: consider two threads incrementing a shared counter x protected by a lock l. The precondition might assert \{l \mapsto \mathit{free} * x \mapsto v\}, with each thread acquiring the lock atomically (\{l \mapsto \mathit{free} * x \mapsto v\} \mathsf{acq}(l); x := x + 1; \mathsf{rel}(l) \{l \mapsto \mathit{free} * x \mapsto v+1\}), ensuring the parallel execution yields \{x \mapsto v+2\} without races, as ownership of the lock serializes access. This demonstrates how separation logic mitigates aliasing issues in concurrent pointer manipulation, promoting modular proofs for larger systems.

Relations to Other Formal Systems

Hoare logic is fundamentally connected to Edsger Dijkstra's weakest calculus, introduced in , which provides a semantic foundation for reasoning about program correctness. In this calculus, the weakest precondition wp(C, Q) denotes the set of states from which executing command C is guaranteed to establish postcondition Q, serving as a predicate transformer that underpins the rules of Hoare logic. The Hoare triple {P} C {Q} holds P implies wp(C, Q), allowing Hoare logic rules to be derived directly from wp semantics, thus unifying axiomatic and transformational approaches to . In contrast to , which interprets programs as mathematical functions mapping initial states to possible final states or sets thereof, Hoare logic offers an axiomatic semantics focused on proof obligations for correctness triples rather than explicit semantic mappings. This operational-style axiomatization emphasizes derivability of assertions through inference rules, whereas , such as those using , provide a compositional for analyzing program behavior, including non-termination. Hoare logic's rules can be justified relative to by showing that valid triples preserve the of programs. Hoare logic has influenced type systems, particularly through embeddings in dependently typed languages like and Agda, where pre- and postconditions are encoded as dependent types to verify imperative code within a functional framework. For instance, Hoare Type Theory integrates assertions into dependent types, enabling polymorphic handling of mutable state while ensuring and correctness properties at the type level. This approach allows Hoare-style specifications to be checked during , bridging imperative with assistants. Hoare logic also informs abstract interpretation, a static analysis technique for approximating program semantics over abstract domains to prove safety properties without full execution traces. The framework, developed by Patrick and Radhia Cousot in 1977, draws on Hoare triples to define sound abstractions of concrete semantics, enabling scalable verification of properties like absence of errors. In contrast, temporal logics such as (LTL) extend beyond Hoare logic's focus on finite, terminating computations to specify liveness and safety in infinite, reactive behaviors, often using for concurrent systems. Furthermore, Hoare logic forms the basis for refinement calculi in like the schema language and B-method, where stepwise refinement transforms abstract specifications into executable code while preserving correctness invariants. These calculi extend Hoare rules to support data refinement and decomposition, facilitating industrial-scale in standards-compliant development.

References

  1. [1]
    [PDF] An Axiomatic Basis for Computer Programming
    “An Axiomatic Basis for Computer. Programming", CACM , 1969. “Procedures and ... Programming Language PASCAL. C.A.R. Hoare and N. Wirth. Acta Informatica 1973.
  2. [2]
    [PDF] Ten Years of Hoare's Logic: A Survey Part l
    A survey of various results concerning Hoare's approach to proving partial and total correctness of programs is presented. Emphasis is placed on the ...
  3. [3]
    [PDF] A SURVEY OF VERIFICATION TOOLS BASED ON HOARE LOGIC
    ( 1 ). Where is a programming language statement or command, and are assertions (variables of) on the space of the program. Such Formulas are called Hoare ...
  4. [4]
    An axiomatic basis for computer programming - ACM Digital Library
    Reference is made to the paper by C. A. R. Hoare [1] which discusses the fundamentals of an axiomatic approach to computer programming. One advantage for an ...Missing: original | Show results with:original
  5. [5]
    [PDF] Assigning meanings to programs - People @EECS
    A verification of an interpretation of a flowchart is a proof that for every command c of the flowchart, if control should enter the command by an entrance a, ...
  6. [6]
    [PDF] An Axiomatic Basis for Computer Programming
    C. A. R. HOARE. **. The Queen's University of Belfast, Northern Ireland. In this paper an attempt is made to explore the logical founda- tions of computer ...
  7. [7]
    [PDF] Fifty Years of Hoare's Logic - arXiv
    Oct 24, 2019 · The adoption of this axiom by Hoare probably influenced a couple of years later Edsger W. Dijkstra to propose the weakest precondition semantics ...
  8. [8]
    [PDF] CS 6110 Lecture 19 Axiomatic Semantics and Hoare Logic 10 ...
    Mar 10, 2025 · In practice we would like to use the weakest possible precondition of c2 that allows proving the second premise. Finally, we need a rule for ...
  9. [9]
    [PDF] Hoare Logic - Ethan Cecchetti
    There are two different notions of correctness, partial and total, that differ based on whether they allow nontermination. • Partial correctness requires that a ...
  10. [10]
    What was the major breakthrough between Hoare-Floyd logic and ...
    May 2, 2017 · The difference between Hoare logic and denotational semantics is that the former is concerned with syntactically ascribing properties of ...
  11. [11]
    [PDF] Hongjin Liang - Hoare Logic
    Dafny proves that code terminates, i.e. does not loop forever, by using decreases annotations. For many things, Dafny is able to guess the right annotations ...
  12. [12]
    [PDF] 1 Hoare Logic 2 Soundness and Completeness
    This result is known as the relative completeness of Hoare logic and is due to Cook (1974). 3 Example: Factorial. As an example illustrating how we can use ...
  13. [13]
    [PDF] Lecture Notes: Hoare Logic
    Thus total correctness is partial correct- ness plus termination. Note that ... the function can behave in any way at all and still be correct.Missing: original | Show results with:original
  14. [14]
    [PDF] Ten Years of Hoare's Logic: A Survey-Part I
    A survey of various results concerning Hoare's approach to proving partial and total correctness of programs is presented. Emphasis is placed on the ...
  15. [15]
    [PDF] Weakest-Precondition Reasoning - UMD Computer Science
    Weakest-Precondition Reasoning. ○ Reference: E.W. Dijkstra, A Discipline of. Programming, Prentice-Hall, 1976. ○ Starting with a post-assertion, what is the ...
  16. [16]
    [PDF] Axiomatic semantics | CS 152 (Spring 2024) | Harvard University
    Apr 2, 2024 · We can use a set of inference rules and axioms, called Hoare rules, to directly derive ... Hoare logic rules (Skip). Skip. ⊢ {P} skip {P}. 23 / 39 ...
  17. [17]
    Lecture 5: Axiomatic Semantics and Hoare Logic — CS 345H
    Hoare logic will give us a way to write down proof rules about programs, prove those rules correct once and for all, and then apply them to any program without ...<|control11|><|separator|>
  18. [18]
    None
    ### Summary of Skip Axiom, Its Role in Composition and Empty Programs
  19. [19]
    Hoare Logic - cs.Princeton
    Nov 3, 2009 · We say that Y <= 4 is the weakest precondition of the command X ::= ! ... the intermediate assertion for a sequential composition c1;c2; the ...
  20. [20]
    [PDF] READABLE PROOFS IN HOARE LOGIC - Carnegie Mellon University
    Mar 25, 2009 · one can calculate a weakest (liberal) precondition pw, which is an assertion such that {p} c {q} holds just when p ⇒ pw. In many such cases ...
  21. [21]
    [PDF] Hoare Logics for Recursive Procedures and Unbounded ... - Isabelle
    both for partial correctness (following Gorelick [6]) and for total correctness ... The consequence rule is like its cousin for partial correctness but with a.
  22. [22]
  23. [23]
    None
    ### While Rule for Total Correctness, Schema with Variant, Explanation, Requirements
  24. [24]
    [PDF] Hoare Logic, Part II Proof Rule for While and Loop Invariants ...
    Hoare Logic, Part II. 4/35. Example. ▷ Consider the statement S = while x < n do x = x + 1. ▷ Let's prove validity of {x ≤ n}S{x ≥ n}. ▷ What is appropriate ...
  25. [25]
    [PDF] Hoare logic Total correctness - University of Cambridge
    We will look at extending partial correctness triples to enforce termination, and at adapting the Hoare logic rules for partial correctness to total correctness ...Missing: original | Show results with:original
  26. [26]
    [PDF] Hoare Logic
    Definition: An assertion language is called expressive if, for every c and q, the weakest precondition wp(c,q) is an assertion in the language. The assertion ...<|control11|><|separator|>
  27. [27]
    [PDF] Lecture Notes: Hoare Logic
    The goal of Hoare logic is to provide a formal system for reasoning about program correctness. Hoare logic is based on the idea of a specification as.Missing: development precursors Floyd
  28. [28]
    [PDF] Lecture Notes: Axiomatic Semantics and Hoare-style Verification
    The goal in Hoare-style verification is thus to (statically!) prove that, given a pre-condition, a particular post-condition will hold after a piece of code ...
  29. [29]
    [PDF] Hoare logic - University of Cambridge
    An invariant for the factorial implementation. {X = x ∧ X ≥ 0 ∧ Y = 1} while X 6= 0 do (Y := Y × X;X := X − 1). {Y = x!} Take I to be Y × X! = x! ∧ X ...
  30. [30]
    Correctness Verification of Aerospace Software Program Based on ...
    Jul 2, 2022 · Then, according to the Hoare logic tripe and its reasoning rules, a module of an aerospace software was verified by artificial reasoning.
  31. [31]
    [PDF] Formal Verification of Safety-Critical Aerospace Systems
    For the verification of the Rotor_check. _threshold program, we used Dafny [13], a verification tool based on Hoare logic [12] that uses the Z3 SMT solver ...<|control11|><|separator|>
  32. [32]
    [PDF] The Dafny Integrated Development Environment - Microsoft
    This paper presents an integrated development environment for Dafny—a programming language, verifier, and proof assistant—that addresses issues present in most ...
  33. [33]
    [PDF] Binary Heaps Formally Verified in Why3 - Hal-Inria
    Oct 26, 2011 · This paper reports on the formal verification of one of these challenges: binary heaps. The solution given here is performed using the Why3 ...Missing: applications | Show results with:applications
  34. [34]
    Formal Methods in Avionic Software Certification: The DO-178C ...
    The paper aims to provide an overview of the above mentioned standard. It highlights key concepts about the proper adoption of formal methods to accomplish the ...
  35. [35]
    [PDF] Formal Verification of Avionics Software Products 1 Introduction
    The first kind of formal technique we consider for the verification of programs is deductive proof based on Hoare logic [15], and the computation of Dijkstra's ...<|separator|>
  36. [36]
    [PDF] Verification of smart contracts: A survey - HAL
    Aug 22, 2022 · When the basic blocks are obtained, the program logic is created using Hoare logic, which has Hoare triple designed for program correctness.
  37. [37]
    [PDF] Scalable SoC Trust Verification using Integrated Theorem Proving ...
    To solve these problems, we propose an integrated formal verification framework where we combine a model checker with an interactive theorem prover for proving.
  38. [38]
    [PDF] Procedures and parameters: An axiomatic approach
    PROCEDURES AND PARAMETERS: AN AXIOMATIC APPROACH by. C. A. R. Hoare. Introduction. It has been suggested, Hoare (1969), that an axiomatic approach to formal.
  39. [39]
    Chapter 14 Hoare logic for control structures - Xavier Leroy
    Program logics as the foundations for deductive verification appear in the famous article An Axiomatic Basis for Computer Programming by Hoare (1969). Instead ...
  40. [40]
    Tentative steps toward a development method for interfering programs
    The proposed method extends specification with postconditions, operation decomposition, and data refinement, using postconditions as predicates of two states.
  41. [41]
    [PDF] An introduction to rely/guarantee reasoning about concurrency
    I Hoare logic: {p}c {q}. I Refinement calculus or B or Event-B: v, x :îp , qó ... The Hoare logic rule for reasoning about a loop, while b do c, for sequential.
  42. [42]
    [PDF] Separation Logic: A Logic for Shared Mutable Data Structures
    Aug 31, 2001 · In joint work with Peter O'Hearn and others, based on early ideas of Burstall, we have developed an extension of. Hoare logic that permits ...
  43. [43]
    [PDF] Resources, Concurrency and Local Reasoning
    In this paper we show how a resource-oriented logic, separation logic, can be used to reason about the usage of resources in concurrent programs. 1 Introduction.
  44. [44]
    [PDF] A semantics for concurrent separation logic
    We introduce a resource-sensitive logic for partial correctness, based on a recent proposal of O'Hearn, adapting separation logic to the concurrent setting. The ...
  45. [45]
    [PDF] RustBelt: Securing the Foundations of the Rust Programming ...
    As discussed in the introduction, Iris is a higher-order separation logic designed to prove correctness of complex concurrent programs. Using Iris to express ...
  46. [46]
    [PDF] Separation Logic and Concurrency (OPLSS 2016) Draft of July 22 ...
    Separation logic is a form of Hoare logic, intended for reasoning about programs with pointers. Let us introduce it by means of an in-place list reversal ...<|control11|><|separator|>
  47. [47]
    [PDF] A Hoare Logic Contract Theory: An Exercise in Denotational ...
    Abstract We sketch a simple theory of Hoare logic contracts for programs with procedures, presented in denotational semantics. In particular, we give a ...
  48. [48]
    [2206.13772] Abstract interpretation, Hoare logic, and incorrectness ...
    Jun 28, 2022 · Abstract interpretation, Hoare logic, and incorrectness (or reverse Hoare) logic are powerful techniques for static analysis of computer programs.
  49. [49]
    [PDF] Z and Hoare Logics
    In this paper I wish to suggest a different approach and that is to use a Hoare logic to bridge the gap between a low-level Z specification and the pro- gram ...