1 / 43

ECI 2007: Specification and Verification of Object-Oriented Programs

ECI 2007: Specification and Verification of Object-Oriented Programs. Lecture 1. The Verifying Compiler. “ A verifying compiler uses automated .. reasoning to check the correctness of the program that it compiles.

jeff
Download Presentation

ECI 2007: Specification and Verification of Object-Oriented Programs

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. ECI 2007: Specification and Verification of Object-Oriented Programs Lecture 1

  2. The Verifying Compiler “A verifying compiler uses automated .. reasoning to check the correctnessof the program that it compiles. Correctness is specified by types, assertions, .. and other redundant annotationsthat accompany the program.” [Hoare, 2004]

  3. Semantics Program VC generation Provability (theorem proving) Validity Specification Theorem in a logic Theorem Proving and Software • Soundness: • If the theorem is valid then the program meets specification • If the theorem is provable then it is valid Meets spec/Found Bug

  4. Spec# Approach for a Verifying Compiler As source language we use C# As specifications we use method contracts, invariants, and also class, field and type annotations As program logic we use Dijkstra’s weakest preconditions For automatic verification we use type checking, verification condition generation (VCG) and automatic theorem proving (ATP)

  5. Demo (Spec#)

  6. Spec# Tool Architecture Spec# (annotated C#) Spec# Compiler Boogie PL VC Generator Formulas Automatic Theorem Prover Z3 SMT solver

  7. Lectures • Logic of Object-oriented Programs • Invariants and Ownership • Verification Condition Generation • Proving Verification Conditions From Spec# To BoogiePL From Boogie PL To Formulas SMT solvers

  8. Programs ! Theorems = Axiomatic Semantics • Consists of: • A language for making assertions about programs • Rules for establishing when assertions hold • Typical assertions: • During the execution, only non-null pointers are dereferenced • This program terminates with x = 0 • Partial vs. total correctness assertions • Safety vs. liveness properties • Usually focus on safety (partial correctness)

  9. Hoare Triples • Partial correctness: { A } s { B} • When you start s in any state that satisfies A • Ifthe execution of s terminates • It does so in a state that satisfies B • Total correctness: [ A ] s [ B ] • When you start s in any state that satisfies A • The execution of s terminates and • It does so in a state that satisfies B • Defined inductively on the structure of statements

  10. Hoare Rules

  11. Hoare Rules: Assignment • Example: { A } x := x + 2 {x >= 5 }. What is A? • General rule: • Surprising how simple the rule is ! • The key is to compute “backwards” the precondition from the postcondition • Forward rule is more complicated:

  12. Weakest preconditions • Dijkstra’s idea: To verify that { A } s { B} • Let Pre(s, B) = {A’ | { A’} s { B} } • b) (Pre(s,B), ) is a lattice • - false  Pre(s,B) • - if Pre(s,B) and Pre(s,B), then Pre(s,B) • - if Pre(s,B) and Pre(s,B), then Pre(s,B) • c) WP(s, B) = lub(Pre(s, B)) • d) Compute WP(s, B) and prove A  WP(s, B)

  13. ) false true weak strong weakest precondition: WP(s, B) A Predicate lattice Pre(s, B)

  14. Weakest preconditions • WP(x := E, B) = B[E/x] • WP(s1; s2, B) = WP(s1, WP(s2, B)) • WP(if E then s1 else s2, B) = E ) WP(s1, B) Æ: E ) WP(s2, B) • WP(assert E, B) = E  B

  15. Example returns c requires true ensures c = a  b bool or(bool a, bool b) { if (a) c := true else c := b } S WP(S, c = a  b) = (a  true = a  b)  (a  b = a  b) Conjecture to be proved: true  (a  true = a  b)  (a  b = a  b)

  16. Weakest preconditions (Contd.) • What about loops? • Define a family of weakest preconditions • WPk(while E do S, B) = weakest precondition from which if the loop terminates in k or fewer iterations, then it terminates in B WP0 = : E ) B WPi+1 = WPi  (E ) WP(s, WPi)) • WP(while E do S, B) = Æk ¸ 0 WPk = glb{WPk | k ¸ 0} • Hard to compute • Can we find something easier yet sufficient ?

  17. verification condition: VC(s, B) Not quite weakest preconditions • Recall what we are trying to do: ) false true Pre(s, B) weak strong weakest precondition: WP(s, B) A • We shall construct a verification condition: VC(s, B) • The loops are annotated with loop invariants ! • VC is guaranteed stronger than WP • But hopefully still weaker than A: A ) VC(s, B) ) WP(s, B)

  18. Desugaring loops • WP(havoc x, B) = x. B • WP(assume E, B) = E  B • whileI,T E do s  assert I; havoc T; assume I; if (E) { s; assert I; assume false } • I is the loop invariant (provided by the programmer) • T is the set of loop targets (can be approximated by scanning the loop body)

  19. Example 1 returns c requires b >= 0 ensures c = a + b int add(int a, int b) { int t; t := b; c := a; assert t  0  c = a+b-t; havoc c,t; assume t  0  c = a+b-t; if (t > 0) { c := c + 1; t := t – 1; assert t  0  c = a+b-t; assume false; } } returns c requires b >= 0 ensures c = a + b int add(int a, int b) { int t; t := b; c := a; invariant t  0  c = a+b-t while (t > 0) { c := c + 1; t := t – 1; } } A A’ L Conjecture to be proved: b  0  VC(A, c = a + b)

  20. returns c requires b >= 0 ensures c = a + b int add(int a, int b) { int t; t := b; c := a; assert t  0  c = a+b-t; havoc c,t; assume t  0  c = a+b-t; if (t > 0) { c := c + 1; t := t – 1; assert t  0  c = a+b-t; assume false; } } • VC(L, c = a + b)  • c,t. (t  0  c = a + b – t  •  t > 0  t - 1  0  • c + 1 = a + b – (t - 1) •  t  0  c = a + b) • VC(A’, c = a + b)  b  0 a = a + b – b  • c,t. (t  0  c = a + b – t  •  t > 0  t - 1  0  • c + 1 = a + b – (t - 1) •  t  0  c = a + b) A’ L Conjecture to be proved: b  0  VC(A’, c = a + b)

  21. Example 2 returns c ensures c = a + b int add(int a, int b) { int t; t := b; c := a; assert c = a+b-t; havoc c,t; assume c = a+b-t; if (t  0) { c := c + 1; t := t – 1; assert c = a+b-t; assume false; } } returns c ensures c = a + b int add(int a, int b) { int t; t := b; c := a; invariant c = a+b-t while (t  0) { c := c + 1; t := t – 1; } } A A’ L Conjecture to be proved: true  VC(A, c = a + b)

  22. Invariants Are Not Easy • Consider the following code from QuickSort int partition(int *a, int L0, int H0, int pivot) { int L = L0, H = H0; while(L < H) { while(a[L] < pivot) L ++; while(a[H] > pivot) H --; if(L < H) { swap a[L] and a[H] } L++; } return L } • Consider verifying only memory safety • What is the loop invariant for the outer loop ?

  23. Verification conditions (Contd.) • What about procedure calls? • Annotate each procedure with a precondition pre, a modifies clause M, a postcondition post • f()  assert pre; havoc M; assume post;

  24. Program verification • Annotate each procedure with a precondition, a modifies clause, and a postcondition and each loop with an invariant and loop targets • Verify each procedure separately requires pre modifies M ensures post f() { S; } Verify that the formula VC(assume pre; S; assert post, true) is valid and the targets of S are contained in M

  25. Exponential Verification Conditions • WP(x := E, B) = B[E/x] • VC(if E then s1 else s2, B) = (E ) VC(s1, B)) Æ (: E ) VC(s2, B)) The following two culprits may result in a VC that is exponential in the size of the program.

  26. s2 if (b1) x := x+1; else x := x+2; . . . if (bn) x := x+1; else x := x+2; VC(s2, x > 1) has at least 2n-1 occurrences of . n statements s1 x := x + x; . . . x := x + x; VC(s1, x > 1) has 2n occurrences of x. n statements

  27. Efficient VC Generation How can we get a formula that is linear in the size of the (loop-free and call-free) program?

  28. Eliminate assignments • Dynamic single assignment (DSA) form • There is at most one definition for each variable on each path • Replace defs/uses with new incarnations • x := x+1 with xn+1 = xn + 1 • Replace havoc x with new incarnations xn+1 • At join points unify variable incarnations • Eliminate assignments by replacing • x := E withassume x = E

  29. Example assume x = 1; x := x + 1; if (x = 0) { x := x + 2; } else { x := x + 3; } assert x = 5 assume x0 = 1; assume x1 = x0 + 1; if (x1 = 0) { assume x2 = x1 + 2; assume x4 = x2; } else { assume x3 = x1 + 3; assume x4 = x3; } assert x4 = 5;

  30. Efficient VC Generation (I) WP(x := E, B) = B[E/x] compare with WP(assume x = E, B) = (x = E  B) Intuition: The decorated variables essentially give names to sub-expressions in the original VC. The unique definition of each variable now occurs as an assumption.

  31. Efficient VC Generation (II) VC(if E then s1 else s2, B) = • E  VC(s1, B) • :E  VC(s2, B) compare with VC(if E then s1 else s2, B) =  E  VC(s1, true)  B  :E  VC(s2, true)  B = •  E  VC(s1, true) • :E  VC(s2, true) B occurs only once in the VC eliminating the exponential blowup.  B

  32. Unstructured control flow • Control flow is not always structured • exceptions, goto statements • How do we generated verification conditions for programs with unstructured control flow?

  33. Unstructured control flow • Eliminate loops, procedure calls, assignments • Passive program with acyclic control flow • Eliminate if-then-else statements using goto statements • Finally, program is a collection of blocks • Each block is • l: A1,…,Am; goto l1,…,ln • l is block label • A is either assume E or assert E • Distinguished “start” label

  34. Example assume x0 = 1; assume x1 = x0 + 1; if (x1 = 0) { assume x2 = x1 + 2; assume x4 = x2; } else { assume x3 = x1 + 3; assume x4 = x3; } assert x4 = 5; start: assume x0 = 1; goto l1; l1: assume x1 = x0 + 1; goto l2, l3; l2: assume x1 = 0; assume x2 = x1 + 2; assume x4 = x2; goto l4; l3: assume x1 0; assume x3 = x1 + 3; assume x4 = x3; goto l4; l4: assert x4 = 5

  35. VC Generation for Unstructured Control Flow For each block A = l: S goto l1,..,ln introduce a boolean variable Aok Aok holds iff all executions starting at A do not end in a failed assertion Introduce a Block Equation for each block A:BEA AokVC(S, BSucc(A). Bok) VC of entire program: (A. BEA)  Startok

  36. Spec# Tool Architecture Spec# (annotated C#) Spec# Compiler Boogie PL VC Generator Formulas Automatic Theorem Prover Z3 SMT solver

  37. Boogie PL: Parts Boogie PL source contains a first order theory to encode the background semantics of the source language and the program, described constants, functions and axioms an imperative part used to encode the traces of the source program, described by procedures, pre and postconditions, mutable variables, and unstructured code

  38. Limits of Boogie PL Boogie PL does not contain • structured types • a heap • expressions with side effects • visibility • subtyping • dynamic dispatch

  39. Declaration procedure Find(xs: [int] int, ct: int, x: int) returns (result: int); Implementation implementation Find(xs: [int] int, ct: int, x: int) returns (result: int) {…} Call call r := Find(bits, 100, 32) Boogie PL: Procedures

  40. Boogie PL: Procedure Specifications • proc Find(xs: [int] int, ct: int, x: int) returns (result: int); • requires ct ≥ 0; • ensures result ≥ 0  result < ct  xs[result] = x; • ensures result < 0  !( i:int :: 0 ≤ i  i < ct  xs[i] = x);

  41. var xs: [int] int; var ct: int; proc Find(x: int) returns (result: int); requires ct ≥ 0; ensures result ≥ 0  result < ct  xs[result]=x; ensures result < 0  !( i:int :: 0 ≤ i  i < ct  xs[i] = x); implFind(x: int) returns (result: int) { start: ct := 0; result := -1; return; } A Bogus Implementation?

  42. Postconditions must say which variables x might change modifies x; variables not mentioned are not allowed to change often relate pre-state and post-state ensures x == old(x)+1; More about Postconditions

  43. proc Find(x: int) returns (result: int); • … • modifies ct; • // would allow the previous implementation • ensuresct == old(ct); • // would disallow the change despite modifies clause

More Related