Loading...

PPT – ECI 2007: Specification and Verification of Object-Oriented Programs PowerPoint presentation | free to view - id: 17bfbd-ZDc1Z

The Adobe Flash plugin is needed to view this content

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. - Correctness is specified by types, assertions,

.. and other redundant annotations that

accompany the program. Hoare, 2004

Theorem Proving and Software

Meets spec/Found Bug

- Soundness
- If the theorem is valid then the program meets

specification - If the theorem is provable then it is valid

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 Dijkstras weakest

preconditions - For automatic verification we use type checking,

verification condition generation (VCG) and

automatic theorem proving (ATP)

Demo (Spec)

Spec Tool Architecture

Spec (annotated C)

Spec Compiler

Boogie PL

VC Generator

Formulas

Automatic Theorem Prover

Z3 SMT solver

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

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)

Hoare Triples

- Partial correctness A s B
- When you start s in any state that satisfies A
- If the 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

Hoare Rules

A s1 C C s2 B

A s1 s2 B

A Æ E s1 B A Æ E s2 B

A if E then s1 else s2 B

I Æ E s I I Æ E ) B

I while E do s B

Hoare Rules Assignment

- Example A x x 2 x gt 5 . What is

A? - General rule

BE/x x E B

- Surprising how simple the rule is !
- The key is to compute backwards the

precondition from the postcondition - Forward rule is more complicated

A x E 9 x. Ax/x Æ x Ex/x

Weakest preconditions

- Dijkstras 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)

Predicate lattice

Pre(s, B)

Weakest preconditions

- WP(x E, B) BE/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

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)

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
- WPi1 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 ?

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)

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)

Example 1

returns c requires b gt 0 ensures c a b int

add(int a, int b) int t t b c

a assert t ? 0 ? c ab-t havoc

c,t assume t ? 0 ? c ab-t if (t gt 0)

c c 1 t t 1

assert t ? 0 ? c ab-t assume false

returns c requires b gt 0 ensures c a b int

add(int a, int b) int t t b c

a invariant t ? 0 ? c ab-t

while (t gt 0) c c 1 t

t 1

A

A

L

Conjecture to be proved b ? 0 ? VC(A, c a b)

returns c requires b gt 0 ensures c a b int

add(int a, int b) int t t b c

a assert t ? 0 ? c ab-t havoc

c,t assume t ? 0 ? c ab-t if (t gt 0)

c c 1 t t 1

assert t ? 0 ? c ab-t assume false

- VC(L, c a b) ?
- c,t.
- (t ? 0 ? c a b t ?
- ? t gt 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 gt 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)

Example 2

returns c ensures c a b int add(int a, int b)

int t t b c a assert c

ab-t havoc c,t assume c ab-t

if (t ? 0) c c 1 t t

1 assert c ab-t assume

false

returns c ensures c a b int add(int a, int b)

int t t b c a

invariant c ab-t while (t ? 0)

c c 1 t t 1

A

A

L

Conjecture to be proved true ? VC(A, c a b)

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 lt H)
- while(aL lt pivot) L
- while(aH gt pivot) H --
- if(L lt H) swap aL and aH
- L
- return L
- Consider verifying only memory safety
- What is the loop invariant for the outer loop ?

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

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

Exponential Verification Conditions

The following two culprits may result in a VC

that is exponential in the size of the program.

- WP(x E, B) BE/x
- VC(if E then s1 else s2, B)

(E ) VC(s1, B)) Æ ( E ) VC(s2, B))

s1 ? x x x . . . x x x

VC(s1, x gt 1) has 2n occurrences of x.

n statements

Efficient VC Generation

How can we get a formula that is linear in the

size of the (loop-free and call-free) program?

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 x1 with xn1 xn 1
- Replace havoc x with new incarnations xn1
- At join points unify variable incarnations
- Eliminate assignments by replacing
- x E with assume x E

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

Efficient VC Generation (I)

- WP(x E, B) BE/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.

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

Unstructured control flow

- Control flow is not always structured
- exceptions, goto statements
- How do we generated verification conditions for

programs with unstructured control flow?

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

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

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

Spec Tool Architecture

Spec (annotated C)

Spec Compiler

Boogie PL

VC Generator

Formulas

Automatic Theorem Prover

Z3 SMT solver

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

Limits of Boogie PL

- Boogie PL does not contain
- structured types
- a heap
- expressions with side effects
- visibility
- subtyping
- dynamic dispatch

Boogie PL Procedures

- 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 Procedure Specifications

proc Find(xs int int, ct int, x int) returns

(result int) requires ct 0 ensures

result 0 ? result lt ct ? xsresult x

ensures result lt 0 ? !(? iint 0 i ? i lt ct

? xsi x)

A Bogus Implementation?

- var xs int int
- var ct int
- proc Find(x int) returns (result int)
- requires ct 0
- ensures result 0 ? result lt ct ?

xsresultx - ensures result lt 0 ? !(? iint 0 i ? i lt

ct ? xsi x) - impl Find(x int) returns (result int)

start ct 0 result -1 return

More about Postconditions

- 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

proc Find(x int) returns (result int)

modifies ct // would allow the previous

implementation ensures ct old(ct) //

would disallow the change despite modifies clause