Advanced Topics in Programming Languages Spring Semester, 2012 Lecture 6: April 24, 2012 Lecturer: Mooly Sagiv Scribe: Michal Balas and Yair Asa

Axiomatic

6.1 The basic idea

The problem we would like to solve is how to prove that a program does what we require of it. Given a program, we specify its required behavior based on our intuitive understanding of it. We can run it according to the or and compare to its behavior there. For some programs we need to be more abstract (for example programs that receive input), and then it is necessary to use some logic to reason about the program (and how it behaves on a set of inputs and not in one specific execution path). In this case we may eventually develop a formal proof system for properties of the program or showing that it satisfies a requirement. We can then use the proof system to show correctness. These rules of the proof system are called Hoare or Floyd-Hoare rules. Floyd-rules are for flow-charts and Hoare-rules are for structured languages. Originally their approach was advocated not just for proving properties of programs but also giving a method for explaining the meaning of program. The meaning of a program was specified in terms of “axioms” saying how to prove properties of it, in other words it is given by a set of verification rules. Therefore, this approach was named axiomatic semantics. Axiomatic semantics has many applications, such as:

Program verifiers • Symbolic execution tools for bug hunting • Software validation tools • Malware detection • Automatic test generation • It is also used for proving the correctness of algorithms or hardware descriptions, “extended static checking (e.g., checking array bounds), and documenting programs and interfaces. 2 Advanced Topics in Programming Languages c Tel Aviv Univ.

6.1.1 Example

P An example program that computes the sum of the first hundred numbers: 1≤m≤100m. S := 0; N := 1; while (N = 101) do ¬ S := S + N; N := N + 1; We can see that the commands S := 0; N := 1; initialize the values in the locations. so we add comments as follows; S := 0; S = 0 N{ := 1;} N = 1 while{ }(N = 101) do ¬ S := S + N; N := N + 1; We can also add the comment after the execution of the while loop meaning that S will have the required value. S := 0; S = 0 N{ := 1;} N = 1 while{ }(N = 101) do ¬ S := S + N; N := N + 1; P N = 101 S = 1≤m≤100m { ∧ } Inside the while loop we add comment on both N and S: N ranges from 1 to 101 and S represents the partial sum. This comment express the key relationship between the value at location S and the value at location N. S := 0; S = 0 N{ := 1;} N = 1 while{ }(N = 101) do ¬ P 1 N < 101 S = 1≤m

P The assertion S = 1≤m≤N m is called an invariant of the while-loop because it remains true under each iteration of the loop.

6.1.2 Partial Correctness and Total Correctness

We can base a proof system on assertions of the form P S Q { } { } where P,Q are assertions, i.e. extensions of boolean expressions, and S is a statement (also called: command). The interpretation of an assertion of this form is: for all states σ which satisfy P , if the execution of S from state σ terminates in state σ0, then σ0 satisfies Q. In other words, any terminating execution of S from a state satisfying P ends up in a state satisfying Q. P is the precondition and Q is the postcondition of the assertion P S Q . For example: y x z := x; z := z + 1 y < z is a valid assertion. { } { } { ≤ } { } Assertions of this form are known as Hoare triples or Hoare assertions, named after the logician C.A.R. Hoare. These assertions are called partial correctness assertions because they do not say anything about the command S if it fails to terminate. An example for a statement that does not terminate when executed from any state is: S while true do skip ≡ Since S does not terminate, true S false is a valid partial correctness assertion. In fact any partial correctness assertion{ for} this{ specific} S is valid. Total correctness assertions, on the other hand, are assertions of the form [P ]S[Q] and the interpretation of such an assertion is: for all states σ which satisfy P , the execution of S from state σ must terminate in a state σ0 that satisfies Q. The semantics of assertions for partial correctness: σ = A means that the state σ satisfies the assertion A (or: A is true at state σ). In| P S Q , the statement S denotes a partial function from initial states to final states. Thus,{ } the{ partial} correctness assertion means: σ, σ0 Σ.(σ = P S, σ σ0) σ0 = Q. By the denotational∀ ∈ semantics:| ∧ h i → ⇒ | σ Σ.(σ = P S S σ = ) S S σ = Q. If we adopt∀ the∈ convention| ∧ thatJ K 6 represents⊥ ⇒ J anK undefined| state that satisfies all assertions, that is, for all A, = A, the partial⊥ correctness assertion P S Q can be defined as follows: σ Σ.σ⊥|= P S S σ = Q. { } { } ∀ ∈ | ⇒ J K | 4 Advanced Topics in Programming Languages c Tel Aviv Univ.

6.2 Assn - an Assertion Language

What kind of assertions should we include? Since we would like to reason about boolean expressions, we include all the assertions in Bexp. We want to make assertions using the quantifiers “ i ” and “ i ”, therefore we work with extensions of Bexp and Aexp which include∀ integer··· variables∃ ··· i over which we can quantify. Then , for example, we use i.k = i l. to denote that an integer k is a multiple of another l. We also import well known∃ mathematical× concepts, for example, we use: n! = n (n 1) 2 1 for the factorial function. × − × · · · × × We first define Aexpv which is, basically, Aexp extended to include integer variables i, j, k, etc.. So Aexpv is given by: a ::= n X i a0 + a1 a0 a1 a0 a1 | | | | − | × where n ranges over numbers, X ranges over locations and i ranges over integer variables. We extend boolean expressions to include these more general arithmetic expressions and quantifiers, as well as implication:

A ::= true false a0 = a1 a0 a1 A0 A1 A0 A1 A A0 a1 i.A i.A | | | ≤ | ∧ | ∨ | ¬ | ⇒ | ∀ | ∃ We call the set of extended boolean assertions, Assn.

6.2.1 Example

A program that computes the gcd of two numbers:

while (M = N) do if¬M N ≤ then N := N M else M := M − N − In this example we would like to say that there are no preconditions (true) and that the postcondition is that M,N both hold the gcd of the original M,N. In order to formulate this we need to add two variables m, n. Now we can set: precondition: (M = m) (N = n) (m 0) (n 0) postcondition: M = N =∧ gcd(m, n)∧ ≥ ∧ ≥ Assn - an Assertion Language 5

6.2.2 Free and Bound Variables An occurrence of an integer variable i in an assertion is bound if it occurs in the scope of an enclosing quantifier i or i. Otherwise, it is free. Examples: ∀ ∃ i.k = i l •∃the occurrence× of the integer variable i is bound, while those of k, l are free. (i + 100 77) ( i.j + 1 = i + 3) • here the≤ same∧ integer∀ variable i has two different occurrences in the same assertion: the first is free and the second is bound. j is free. A formal definition using definition by structural induction: Let FV (a) be the set of free variables of arithmetic expressions, extended by integer variables (a Aexpv). By structural induction: ∈ FV (n) = FV (X) = FV (i) = i ∅ { } S FV (a0 + a1) = FV (a0 a1) = FV (a0 a1) = FV (a0) FV (a1) for all numbers n, locations X, and− integer variables× i. Let FV (A) be the free variables of an assertion A. By structural induction: FV (true) = FV (false) = ∅ S FV (a0 = a1) = FV (a0 a1) = FV (a0) FV (a1) ≤ S FV (A0 A1) = FV (A0 A1) = FV (A0 A1) = FV (A0) FV (A1) FV ( A∧) = FV (A) ∨ ⇒ FV (¬i.A) = FV ( i.A) = FV (A) i ∀ ∃ \{ } for all a0, a1 Aexpv, integer variables i and assertions A0,A1,A. Any variable∈ which occurs in an assertion A and is not free is said to be bound. An assertion with no free variables is closed.

6.2.3 Substitution Visualization of an assertion A, with free occurrences of integer variable i: --- i --- i ---- Let a be a “pure” arithmetic expression (contains no integer variables). Then the result of substituting a for i is: A[a/i] --- a --- a ---- ≡ In general substitutions, if a contains integer variables then it may be necessary to rename some bound variables of A in order to avoid some variables of a becoming bound by quantifiers in A. Let i be an integer variable and a an arithmetic expression without integer variables. We use structural induction to define substitution into arithmetic expressions: 6 Advanced Topics in Programming Languages c Tel Aviv Univ.

n[a/i] n X[a/i]≡ X j[a/i] ≡j i[a/i] ≡ a ≡ (a0 + a1)[a/i] (a0[a/i] + a1[a/i]) ≡ (a0 a1)[a/i] (a0[a/i] a1[a/i]) − ≡ − (a0 a1)[a/i] (a0[a/i] a1[a/i]) × ≡ × when n is a number, X a location, j an integer variable (j = i) and a0, a1 Aexpv. Now we define substitutions of a (no free variables in a) for i in assertions:6 ∈ true[a/i] true false[a/i]≡ false ≡ (A0 = A1)[a/i] (A0[a/i] = A1[a/i]) ≡ (A0 A1)[a/i] (A0[a/i] A1[a/i]) ≤ ≡ ≤ (A0 A1)[a/i] (A0[a/i] A1[a/i]) ∧ ≡ ∧ (A0 A1)[a/i] (A0[a/i] A1[a/i]) ( A∨)[a/i] (≡A[a/i]) ∨ ¬ ≡ ¬ (A0 A1)[a/i] (A0[a/i] A1[a/i]) ( j.A⇒)[a/i] ( ≡j.A[a/i]) ⇒ (∀i.A)[a/i] ≡ (∀i.A) (∀j.A)[a/i] ≡ (∀j.A[a/i]) (∃i.A)[a/i] ≡ (∃i.A) ∃ ≡ ∃ where a0, a1 Aexpv, A0,A1,A are assertions and j is an integer variable with j = i. For substitution∈ in place of a location X we use the same notation. The formal definition6 is similar to the one above. A --- X --- X ---- A[a/X≡ ] --- a --- a ---- ≡ Example Assertions:

i is a prime number: • PRIME j, k . j k = i (j = 1 k = 1) ≡ ∀ × ⇒ ∨

i is the least common multiple of j, k: • LCM i = ( j k /gcd(j, k)) ≡ | × |

6.3 Semantics of Assertions

The extended arithmetic expressions include integer variables. In order to describe the value of such an expression we must first interpret integer variables as particular integers. Semantics of Assertions 7

An interpretation is a function assigning integer to each integer variable: I :Intvar N. → The meaning of Aexpv: We define a semantic function Av giving the value of an arithmetic expression a with integer variables in a particular state σ in a particular interpretation I. It is written as Av a Iσ or (Av a (I))(σ). It is defined by structural induction: J K J K Av n Iσ = n AvJXK Iσ = σ(X) AvJi IσK = I(i) AvJaK0 + a1 Iσ = Av a0 Iσ + Av a1 Iσ AvJa0 a1KIσ = AvJa0KIσ AvJa1KIσ − − AvJa0 a1KIσ = AvJa0KIσ AvJa1KIσ J × K J K × J K This extends the semantics for arithmetics expressions without integer variables. For all a Aexp, for all states σ and for all interpretations I A a∈σ = Av a Iσ J K J K The meaning of Assn: The semantic function requires an interpretation function as a further argument, since inte- ger variables are included. The interpretation function provides a value in N, which is the interpretation of integer variables. We use I[n/i] to define the interpretation got from I by changing the value of i to n. We can specify the meaning of assertions in Assn in the same way we did for expressions in Aexpv using a semantics function. Or given an interpretation I define directly the states which satisfy an assertion.

We extend the set of states Σ to the set Σ⊥ which includes the value for non-terminating computation. By structural induction we define when σ =I A (A Assn⊥ ), i.e., when state σ satisfies A in interpretation I. Then we extend it so| =I A.∈ We define by structural induction for all σ Σ: ⊥| σ =I true∈ | I σ = (a0 = a1) if Av a0 Iσ = Av a1 Iσ | I σ = (a0 a1) if AvJa0KIσ AvJa1KIσ σ |=I A ≤B if σ =I AJ andK σ≤=I BJ K σ |=I A ∧ B if σ |=I A or σ =|I B σ |=I A∨if not σ| =I A | σ |=I A¬ B if (not| σ =I A) or σ =I B | ⇒ | | σ =I i.A if σ =I[n/i] A for all n N | ∀ | ∈ σ =I i.A if σ =I[n/i] A for some n N |=I A∃ | ∈ ⊥| The semantics of boolean expressions (which are certain kinds of assertions): For all b ∈ 8 Advanced Topics in Programming Languages c Tel Aviv Univ.

Bexp, for all states σ and for all interpretations I B b σ = true iff σ =I b, and BJbKσ = false iff not| σ =I b J K | 6.3.1 Partial Correctness Assertions The partial correctness, as defined in subsection 6.1.2, does not interest us as programmers, since finding out whether it is true at a particular state is not that important to us. What will usually be more interesting is whether it is true at all states. This will be discussed next.

6.3.2 Validity Let I be an interpretation and consider P c Q . We want this partial correctness assertion to be true at all states with respect to the{ } interpretation{ } I, i.e. I σ Σ⊥.σ = P c Q or: ∀ ∈ | { } { } =I P c Q In fact, we| are{ interested} { } to know whether or not it is true at all states for all interpretations I, i.e. = P c Q | { } { } This is called the validaity. When = P c Q we say the partial correctness assertion P c Q is valid. | { } { } { }For{ example,} consider i < X X := X + 1 i < x { } { } we are interested in whether or not it is true at all states for all interpretations I rather then in a particular value associated with i by the interpretation I. Similarly, for any assertion A we say = A iff for all interpretations I and states σ, σ =I A. Then A is valid. | |

6.3.3 Examples Suppose = (P Q). • Then for| any interpretation⇒ I σ Σ.((σ =I P ) (σ =I Q)) ∀ ∈ | ⇒ | i.e. P I QI . So = (⊆P Q) iff for all interpretations I, all states which satisfy P also satisfy Q. | ⇒ Suppose = P c Q . • Then for| any{ interpretation} { } I Proof Rules for Partial Correctness 9

QI P I Σ ⊥

σ Σ.((σ =I P ) (C c σ =I Q)) ∀ ∈ | ⇒ | i.e. the image of P under C c isJ includedK in Q, i.e. C c P I QI . J K J K ⊆

C[[c]] P I QI Σ ⊥

So = P c Q iff for all interpretations I, if c is executed from a state which satisfies A then| { if} its{ execution} terminates in a state, that state will satisfy B. Remark: P I and QI are not necessarily disjoint.

6.4 Proof Rules for Partial Correctness

Hoare rules are a set of proof rules that are syntax-directed. This rules reduce proving a par- tial correctness assertion of a compound command to proving partial correctness assertions of its immediate subcommands. 10 Advanced Topics in Programming Languages c Tel Aviv Univ.

6.4.1 Hoare Proof Rules for Partial Correctness 1. Rule for skip: A skip A { } { } 2. Rule for assignments: B [a/X] X := a B { } { } A c0 C C c1 B 3. Rule for sequencing: { } { }{ } { } A c0; c1 B { } { } A b c0 B A b c1 B 4. Rule for conditionals: { ∧ } { }{ ∧ ¬ } { } A if b then c0 else c1 B { } { } A b c A 5. Rule for while loops: { ∧ } { } A while b do c A B { } { ∧ ¬ } = (A A0) A0 c B = (B B0) 6. Rule of consequence: | → { } { } | → A c B { } { } 6.5 Example - Using Hoare rules

Y := 1; while X > 0 do Y := X Y ; X := X ∗ 1; −

This code computes n! where n is the initial value of X. We will use Hoare’s rules to prove this. We begin by setting our precondition : P := X = n n 0 { ∧ ≥ }

Now we go to the first statement : Y := 1; This is assignment so we will use rule no. 2 : X = n n 0 Y := 1; X = n Y = 1 n 0 { ∧ ≥ } { ∧ ∧ ≥ }

We need the postcondition to match the precondition of the next statement (While) so can latter use rule no. 3. Therefore we will now use rule no. 6 : X = n n 0 Y := 1; X 0 n 0 Y = n!/X! { ∧ ≥ } { ≥ ∧ ≥ ∧ } Example - Using Hoare rules 11

We move on to next statement which is the while. We begin with it’s most inner statements. Therefore we begin with Y := X Y ; using rule no. 2: ∗ X 0 n 0 Y = n!/X! Y := X Y ; X > n n 0 Y = n!/(X 1)! { ≥ ∧ ≥ ∧ } ∗ { ∧ ≥ ∧ − }

In the same way we do statement X := X 1; : − X > 0 n 0 Y = n!/(X 1)! X := X 1; X 0 n 0 Y = n!/X! { ∧ ≥ ∧ − } − { ≥ ∧ ≥ ∧ }

We combine the two using rule no. 3 :

X 0 n 0 Y = n!/X! Y := X Y ; X := X 1; X 0 n 0 Y = n!/X! { ≥ ∧ ≥ ∧ } ∗ − { ≥ ∧ ≥ ∧ }

In order to use rule no. 5 on the loop we need the precondition of the inner statement to match the invariant and the boolean condition. Therefore we will now use rule no. 6 on the last statement :

X 0 n 0 Y = n!/X! X > 0 Y := X Y ; X := X 1; X 0 n 0 Y = n!/X! { ≥ ∧ ≥ ∧ ∧ } ∗ − { ≥ ∧ ≥ ∧ }

No we can use rule no. 5 on the while statement:

X 0 n 0 Y = n!/X! while X > 0 do Y := X Y ; X := X 1; X 0 n 0 Y = n!/X! X > 0 { ≥ ∧ ≥ ∧ } ∗ − { ≥ ∧ ≥ ∧ ∧ 6 }

We will use rule no. 6 on the while statement in order for the postcondition the match the final wanted result:

X 0 n 0 Y = n!/X! while X > 0 do Y := X Y ; X := X 1; Y = n! { ≥ ∧ ≥ ∧ } ∗ − { }

Lastly we will combine the while with first statement using rule no. 3 to get the complete proof:

X = n n 0 Y := 1; while X > 0 do Y := X Y ; X := X 1; Y = n! { ∧ ≥ } ∗ − { } 12 Advanced Topics in Programming Languages c Tel Aviv Univ.

6.6 Soundness

Every rule should preserve validity, in the sense that if the assumptions in the rule’s premise is valid then so is its conclusion. When this holds of a rule it is called sound. When every rule of a proof system is sound, the proof system itself is said to be sound. It follows then by rule-induction that every theorem obtained from the proof system of Hoare rules is a valid partial correctness assertion. The proof of soundness of the rules depends on some facts about substitution. Lemma 6.8: Let I be an interpretation. Let a, a0 Aexpv. Let X XLoc. Then for all interpretions I and states σ ∈ ∈

Av[[a0[a/X]]]Iσ = Av[[a0]]Iσ[Av[[a]]Iσ/X]

Lemma 6.9: Let I be an interpretation. Let B Assn, X Loc and a Aexp. For all states σ Σ ∈ ∈ ∈ ∈ I I σ = B[a/X]iffσ[A[[a]]σ/X] = B. | |

Theorem: Let A c B be a partial correctness assertion. If A c B then A c B . { } { } ` { } { } { } { } Proof: Clearly if we can show each rule is sound (i.e preserves validity in the sense that if its premise consists of valid assertions and partial correctness assertions then so is its con- clusion) then by rule-induction we can see that every theorem is valid.

The rule for skip : Clearly = A skip A so the rule for skip is sound. | { } { } The rule for assignment: Assume c (X := a). Let I be an interpretation. We have≡ σ =I B[a/X] iff σ[A[[a]]σ/X] =I B, by Lemma 6.9 Thus.σ =I B[a/X] C[[X := a]]σ |=I B, and hence = B[a/X] X;| = a B , showing the soundness| of the assignment→ rule. | | { } { }

The rule for sequencing: Assume = A c0 C and = C c1 B . Let I be an interpretation. Suppose| { σ}={I A}. Either| {σ }=I{b }or σ =I b. In the former I I I| | | ¬ I case σ = A b so C[[c0]]σ = B, as = A b c0 B . In the latter case σ = A b so | I ∧ I | | { ∧ } { } | ∧ ¬ C[[c1]]σ = B, as = A b c1 B . This ensures = A if b then c0 else c1 B | | { ∧ ¬ } { } | { } { } The rule for while-loops: Assume = A b c A , i.e. A is an invariant. w while b do c. | { ∧ } { } ≡ 0 Let I be an interpretation. Recall that C[[w]] = n∈wΘn where Θ0 = Θ, Θn+1 = (σ, σ ) B[[b]]σ = 0 0 ∪ { | true and (σ, σ ) Θn C[[c]] (σ, σ B[[b]]σ = false) ∈ ◦ } ∪ { | } Ideal Completeness 13

We shall show by mathematical induction that P (n) holds where P (n) def ∀σ,σ0 ∈Σ(σ, σ0) I 0 I ↔ ∈ Θn and σ = A σ = A b | → | ∧ ¬ For all =I A = C[[ω]]σ =I A b | | | ∧ ¬ For all states σ, and hence that = A ω A b , as required. | { } { ∧ ¬ }

Base case n = 0;When n = 0, Θ0 = so that induction hypothesis P (0) is vacuously true. ∅ Induction Step: We assume the induction hypothesis P (n) holds for n 0 and attempt 0 I ≥ to prove P (n + 1). Suppose (ω, ω ) Θn+1 and ω = A. Either (i)B[[b]]ω = true and 0 ∈ 0 | (ω, ω ) Θn C[[c]], or (ii)B[[b]]ω = false and ω = ω ∈ ◦ We show in either case that ω0 =I A b. Assume (i). As B[[b]]ω = true we have ω =I b I | 00 ∧ ¬ 00 0 00 | and hence ω = A b. Also (ω, ω ) C[[c]] and (ω , ω ) Θn for some state ω . We obtain ω0 =I A, as =| A ∧b c A . From the∈ assumption P (n),∈ we obtain ω0 =I A b. Assume| (ii).| As{ B∧[[b]]}ω{=}false we have ω =I b and hence ω =I A| b∧. ¬ But ω0 = ω. This establishes the induction hypothesis P (n|+ 1).¬ By mathematical| induction∧ ¬ we conclude P (n) holds for all n. Hence the rule for while loops is sound.

The consequence rule: Assume = (A A0) and = A0 c B0 and = (B0 B). Let I be an interpretation. Suppose| ω→ =I A. Then| { ω}I A{0, hence} C| [[c]]ω →=I B0 and hence C[[c]]ω =I B. Thus A c B . The consequence| rule is sound. | | { } { } By rule-induction, every theorem is valid.

6.7 Ideal Completeness

G¨odel’sIncompleteness Theorem implies there is no complete proof system for establishing precisely the valid assertions. The Hoare rules inherit this incompleteness. However by separating incompleteness of the assertion language from incompleteness due to inadequacies in the axioms and rules for the programming language constructs, we can obtain relative completeness. The proof that Hoare rules are relatively complete relies on the idea of weakest liberal precondition, and leads into a discussion of verification-condition generators. 14 Advanced Topics in Programming Languages c Tel Aviv Univ.

6.7.1 Weakest Precondition Definition: wp(c,Q) - the weakest condition such that every terminating computation of s results in a state satisfying Q.

[[wpI (c, Q)]] = σ Σ⊥ S[[c]]σ I Q { ∈ | ∈ }

Theorem: Assn is expressive Proof: We show by structural induction on commands c that for all assertions B there is an assertion w[[c,B]] such that for all interpretations I

wpI [[c, B]] = w[[c, B]]I for all commands c. For example we will show the if command : c if b then c0 else c1 : Define ≡

w[[if b then c0 else c1,B]] [(b w[[c0,B]])] [( b w[[c1,B]])] ≡ ∧ ∨ ¬ ∧

Then, for σ Σ and interpretation I, ∈ σ wpI [[c, B]] iff [[c]]σ =I B ∈ C | iff I ([ [[b]]σ = true and [[c0]]σ = B] B C | or I ([ [[b]]σ = false and [[c1]]σ = B] B C | iff I I (σ = b and σ = w[[c0,B] | | or I I (σ = b and σ = w[[c1,B] | ¬ | , by induction iff σ = I[(b w[[c0,B]])] [( b w[[c1,B]])] | ∧ ∨ ¬ ∧ iff σ = Iw[[c, B]] |

Lemma: For command c and B Assn, let w[[c,B]] be an assertion expressing the weakest precondition i.e. w[[c, B]]I = wpI∈[[c, B]]. Then

w[[c, B]] c B { } { } Ideal Completeness 15

Proof: Let w[[c,B]] be an assertion which expresses the weakest precondition of a command c and postcondition B. We show by structural induction on c that

w[[c, B]] c B for all B Assn ` { } { } ∈ for all commands c. For example we will show the if command : c if b then c0 else c1 : In this case, for σ Σ and interpretation I, ≡ ∈ σ = Iw[[c, B]] iff [[c]]σ =I B | C | iff I ([ [[b]]σ = true and [[c0]]σ = B] B C | or I ([ [[b]]σ = false and [[c1]]σ = B] B C | iff I I (σ = b and σ = w[[c0,B] | | or I I (σ = b and σ = w[[c1,B] | ¬ | iff

σ = I[(b w[[c0,B]])] [( b w[[c1,B]])] | ∧ ∨ ¬ ∧ Hence

= w[[c, B]] [(b w[[c0,B]]) [( b w[[c1,B]] | ⇔ ∧ ∨ ¬ ∧

Theorem: The proof system for partial correctness is relatively complete, i.e. for any partial correctness assertion A c B , { } { } A c B if = A c B ` { } { } | { } { }

Proof: Suppose = A c B . Then by the above lemma w[[c, B]] c B where w[[c, B]]I = wpI [[c, B]] for any| { interpretation} { } I. Thus as = (A w`[[c, { B]]), by} the{ } consequence rule, we obtain = A c B . | ⇒ | { } { } 16 Advanced Topics in Programming Languages c Tel Aviv Univ.

6.7.2 Verification Conditions

Since Assn is expressive, the validity of a partial correctness assertion of the form P c Q is equivalent to the validity of the assertion A w c, B , from which the command{ } { has} been eliminated. In this way, given a theorem prover⇒ J forK predicate calculus we may hope to derive a theorem prover for our programs. Unfortunately, obtaining w c, B is inefficient and not practical. J K

However, we can use automatic theorem provers to show partial correctness and to check the validity of such assertions. We start by generating assertions that describe the partial correctness of the program. This is also referred to as annotating the program by assertions. We define the syntactic set of annotated commands by: c ::= skip X := a c0;(X := a) c0; D c1 | | | { } | if b then c0 else c1 while b do D c | { } where X is a location, a an arithmetic expression, b a boolean expression, c, c0, c1 are anno- tated commands and D is an assertion such that in c0; D c1, the annotated command c1 is not an assignment. { } The general idea: an assertion at a point in the annotated command is true whenever flow of control reaches that point. Thus we only annotate commands of the form c0; c1 at the point where the control shifts from c0 to c1. When c1 is an assignment the annotation can be derived simply from a postcondition.

An annotated partial correctness assertion is of the form A c B where c is an annotated command. We can say that an annotated partial correctness{ } { assertion} is valid when its associated (unannotated) partial correctness assertion is. For example, the following annotated while loop: A while b do D c B { } { } { } contains an assertion D which we hope is an invariant, meaning that: D b c D is valid.{ ∧ } { } In order to ensure that A while b do D c B { } { } { } is valid, if D is an invariant, it suffices to show that both: A D, D b B are valid.⇒ ∧ ¬ ⇒ We can derive A while b do c B from D b c D using the Hoare rules. { } { } { ∧ } { } Not all annotated partial correctness assertions are valid. We define the verification con- ditions (vc) by structural induction of annotated commands: Summary 17

vc( A skip B ) = A B vc( A{X}:= a{B}) = {A ⇒ B}[a/X] { } { } { ⇒ } vc( A c0; X := a B ) = vc( A c0 B[a/X] ) { } { } { } { } vc( A c0; D c1 B ) = vc( A c0 D ) vc( D c1 B ) { } { } { } { } { } ∪ { } { } where c1 is not an assignment vc( A if b then c0 else c1 B ) = vc( A b c0 B vc( A b c1 B ) vc{( }A while b do D c{B}) = vc({D ∧ b}c {D }) ∪ A{ ∧D ¬ } D{ } b B { } { } { } { ∧ } { } ∪ { ⇒ } ∪ { ∧ ¬ ⇒ } To show that an annotated partial correctness assertion is valid it is sufficient to show its verification conditions are valid. Thus, the program verification can be done by the theorem prover for predicate calculus. An example for such a program is Gypsy(CITE). While validity of verification conditions is sufficient to guarantee the validity of an an- notated partial correctness assertion - it is not necessary (can happen when the invariant chosen is in appropriate for the pre and post conditions). Example: true while false do false skip true The above{ annotated} while-loop{ } is valid{ with} false as an invariant. However, its verification conditions contain: true false which is not⇒ a valid assertion.

Various theorem-provers:

Z3 - http://research.microsoft.com/en-us/um/redmond/projects/z3/ • Isabelle - http://isabelle.in.tum.de/nominal/activities/cas09/ • ESC/Java - http://en.wikipedia.org/wiki/ESC/Java • Spec# - http://research.microsoft.com/en-us/projects/specsharp/ • 6.8 Summary

Axiomatic semantics provides an abstract semantics. It is appropriate for arguing program correctness, and therefore can be used to explain programming. It has many extensions, such as:

Procedures • Concurrency • Events • 18 Advanced Topics in Programming Languages c Tel Aviv Univ.

Rely/Guarantee • Heaps • There are many automatic tools based on axiomatic semantics for various applications, e.g. theorem-provers and program verifiers. However, more effort is required to make it more efficient and practical.

6.9 Further Reading

Glynn Winskel. The formal semantics of programming languages: an introduction. • MIT Press, Cambridge, MA, USA, 1993. (Chapters 6 and 7)