62
Formal techniques for getting software right: some old ideas and some new tools Applied Formal Methods Research Group 2012-11-02 David Lightfoot: [email protected] Department of Computing and Communication Technologies Oxford Brookes University England

Formal techniques for getting software right: some old ideas and some new tools

  • Upload
    deidra

  • View
    24

  • Download
    2

Embed Size (px)

DESCRIPTION

Formal techniques for getting software right: some old ideas and some new tools. Applied Formal Methods Research Group 2012-11-02 David Lightfoot: [email protected] Department of Computing and Communication Technologies Oxford Brookes University England. Abstract. - PowerPoint PPT Presentation

Citation preview

Page 1: Formal techniques for getting software right: some old ideas and some new tools

Formal techniques for getting software right: some old ideas and some new tools

Applied Formal Methods Research Group

2012-11-02

David Lightfoot: [email protected]

Department of Computing and Communication Technologies

Oxford Brookes University

England

Page 2: Formal techniques for getting software right: some old ideas and some new tools

Abstract

Getting software right is difficult and the more so if we don’t have a clear idea of what it is supposed to do before we start writing it.

There are some simple ideas that were devised nearly fifty years ago that help in specifying formally what software is to do, that is, by the use of simple discrete mathematics.

These ideas are gaining acceptance in programming languages and modern languages, such as Eiffel and Spec# (‘spec sharp’) now contain features to make use of these ideas.

Page 3: Formal techniques for getting software right: some old ideas and some new tools

Motivating example: hotel

What does ‘available’ mean?

Check rooms available at affordable hotel:

‘18 rooms available’

Book (expensive) flight.

Try to book rooms:

‘Sorry, no rooms available’

Problem!

Check rooms available at affordable hotel, again:

‘18 rooms available’

What is the explanation?

Page 4: Formal techniques for getting software right: some old ideas and some new tools

Motivating example: hotel

Hotel closed for Christmas break!

So, no rooms booked, hence

‘18 rooms available’

But hotel closed, so

‘Sorry, no rooms available’

What does ‘available’ mean?

Page 5: Formal techniques for getting software right: some old ideas and some new tools

We need specifications!

What does ‘available’ mean?

Here’s another one: (from an exam paper):

‘Write a Pascal program to return a pointer to the element in the linked list ls that has key value x:

function Find(ls: Pointer; x: integer): Pointer;’

•What if there isn’t one? Can we assume there is?•Which one, if there are several?

Answer: return NIL. Why?

Page 6: Formal techniques for getting software right: some old ideas and some new tools

What’s the requirement?

‘Write a program to input a three integer numbers, each of them is between 1 and 1000, and determine whether the first number is the multiple of the other two numbers.

Print a message to tell if the first number is the multiple of the other two numbers. [22 marks]’

8 of the 22 marks were for checking that the three integer numbers were in range 1 to 1000 and writing a message. (But it says ‘each of them is …’).

(and no marks for checking that a well formed integer was input)

Page 7: Formal techniques for getting software right: some old ideas and some new tools

Campaign for clear specifications

In order to write correct programs we need clear specifications:•A program is syntactically correct with respect to its language definition•It is logically/semantically correct with respect to its specification

We can check syntactic correctness with a (correct) compiler.

We can check logical correctness by:•testing•use of suitable notation and of provers

Page 8: Formal techniques for getting software right: some old ideas and some new tools

State-based specification

Both at the system level and at program level we can specify by a state-based approach:•Observe state of system before an operation•Observe state of system after an operation

This puts emphasis on what is achieved, not how it is achieved.

Specification notations, such as:

Z, VDM, B, Event B …

Page 9: Formal techniques for getting software right: some old ideas and some new tools

Not a new idea: Professor Sir Tony Hoare

Formerly Head of Programming Research Group (PRG), Oxford University, EnglandSenior Researcher, Microsoft Research, Cambridge, England

Hoare, C.A.R.: An axiomatic basis for computer programming. Communications of the ACM 12 (1969) 576-580 [WH66]

N. Wirth and C. A. R. Hoare. A contribution to the development of Algol. Comm. ACM, 9(6):413-432, June 1966

Also famous as deviser of Quicksort.

Page 10: Formal techniques for getting software right: some old ideas and some new tools

‘Hoare triple’

{ pre }

prog

{ post }

Starting in a before-state where the Boolean expression pre holds, running the program prog results in an after-state where the Boolean expression post holds.

pre is ‘precondition’

post is ‘postcondition’

Page 11: Formal techniques for getting software right: some old ideas and some new tools

Example

{ x >= 0 }

IntegerSqrt

(z*z <= x and x < (z+1)*(z+1)

Precondition means:

IntegerSqrt is only applicable to non-negative x

Postcondition means

z has been set to the ‘integer square-root’ of x

Page 12: Formal techniques for getting software right: some old ideas and some new tools

Specification of a function

function IntegerSqrt(x: integer): integer;

{ pre: x >= 0

post: result*result <= x and x < (result+1)*(result+1) }

result is here a special key word denoting the result of a function

Page 13: Formal techniques for getting software right: some old ideas and some new tools

Techniques for programming

Hoare developed techniques based on axioms (rules) for devising programs that can be shown (proved) to satisfy their specifications.

Page 14: Formal techniques for getting software right: some old ideas and some new tools

Assignment axiom

(* P[var/exp ] *)

var := exp

(* P *)

If P is true of var after the assignment, then P must have been true of exp before.

P[var/exp ] means P, with all (free) occurrences of var replaced by exp.

Page 15: Formal techniques for getting software right: some old ideas and some new tools

Composition axiom

if we can prove (* P *) S1 (* Q *) and we can prove (* Q *) S2 (* R *)

___________then it follows that (* P *) S1 ; S2 (* R *)  If doing S1 when P is true makes Q true and doing S2 when Q is true makes R true, then doing S1 ; S2 when P is true makes R true.

Page 16: Formal techniques for getting software right: some old ideas and some new tools

Selection axiom

(* P & guard *) S1 (* Q *) (* P & ¬guard *) S2 (* Q *)___________(* P *) if guard then S1 else S2 end (* Q *)

If performing S1 when P is true and guard is true makes Q true and performing S2 when P is true and guard is false makes Q true, Then performing

if guard then S1 else S2 end when P is true makes Q true.

Page 17: Formal techniques for getting software right: some old ideas and some new tools

Repetition axiom

(* pre *)initialisation(* invariant *)while guard do (* invariant & guard *) body (* invariant *)end(* invariant & ~guard => post *)

Page 18: Formal techniques for getting software right: some old ideas and some new tools

Dijkstra

E.W.Dijkstra observed that rather than proving an existing program correct, it is easier to develop a program hand-in-hand with showing it to be correct.

Developed weakest-precondition, wp notation

For example:

wp(var := exp, P) is P[var/exp ]

Also famous for P and V and Travelling-Salesman problem, …

Page 19: Formal techniques for getting software right: some old ideas and some new tools

What’s the precondition?: a real example

Recent student work:

Required to implement undo.

Keep stack of visited nodes.

Undo then means pop from stack.

In method undo, do we need to guard with:

if(!stack.isEmpty()) node = stack.pop(); ?

Or do we have precondition: !stack.isEmpty(),

so can just implement undo as:

node = stack.pop(); ?

Page 20: Formal techniques for getting software right: some old ideas and some new tools

Design by Contract™

Hoare’s ideas given a business flavour by Bertrand Meyer, currently Professor of Software Engineering at ETH Zurich.

Precondition and postcondition are expressed as a contract between the supplier and the client of a service.

Also designer of Eiffel programming language.

Eiffel contains facilities for run-time checking of precondition and postcondition…

Page 21: Formal techniques for getting software right: some old ideas and some new tools

IntegerSqrt as contract: supplier’s view

Supplier is writer of IntegerSqrt

Supplier’s expectation:

x >= 0

Supplier’s obligation:

must deliver result such that

result*result <= x and x < (result+1)*(result+1)

Page 22: Formal techniques for getting software right: some old ideas and some new tools

IntegerSqrt as contract: client’s view

Client is user of IntegerSqrt

Client’s expectation:

obtains result such that

result*result <= x and x < (result+1)*(result+1)

Client’s obligation:

give x such that

x >= 0

Page 23: Formal techniques for getting software right: some old ideas and some new tools

integerSqrt in Eiffel

integerSqrt (x: INTEGER) : INTEGER-- return the integer square-root of non-negative x

requirenon-negative_x:

x >= 0ensure

result is floor of square-root of x:result*result <= x and x < (result+1)*(result+1)

Page 24: Formal techniques for getting software right: some old ideas and some new tools

Embodied in Eiffel

The ideas of pre- and post-conditions are embodied in the keywords require and ensure in the Eiffel programming language.

Eiffel compilers embed code to test these at run time (can be selectively turned on and off by compiler switches).

Failure leads to diagnostic information being displayed.

Page 25: Formal techniques for getting software right: some old ideas and some new tools

Use of assert

We can simulate the effects of require and ensure by use of assert statement, provided by many programming-language implementations:

assert(b), where b is a Boolean expression.•If b is true, all is well•If b is false, program halted and message displayed.

Sometimes assert has a second parameter, which is message to be displayed.

Page 26: Formal techniques for getting software right: some old ideas and some new tools

Example of use of assert

function IntegerSqrt(x: integer): integer;

begin

assert (x >= 0);

calculate result

assert (result*result <= x and x < (result+1)*(result+1) );

return result;

end;

Page 27: Formal techniques for getting software right: some old ideas and some new tools

A new style of programming: ‘offensive’!

Practical context for the ‘formal’, Hoare style.

An ‘attitude’ – the opposite of ‘defensive programming’ – Meyer calls it ‘offensive programming!’.

Pre- and post-conditions are used to specify a (business) contract between the supplier of a software component and the component’s clients.

Design by Contract by Example, Richard Mitchell and Jim McKim, Addison Wesley, 2002

Since ‘Design by Contract’ is a trademark, it is often referred to as 'Programming by Contract'.

Page 28: Formal techniques for getting software right: some old ideas and some new tools

New style

With Design by Contract™ we don’t check preconditions:

Responsibility of client to ensure.

Example:function DaysEarlier(y1, m1, d1, y2, m2, d2: integer); integer;

{ return number of days by which

date y1-m1-d1 is earlier than date y2-m2-d2}

Page 29: Formal techniques for getting software right: some old ideas and some new tools

This formalised as …

function DaysEarlier(y1, m1, d1, y2, m2, d2: integer); integer;

{ require

y1-m1-d1 denotes a date and

y2-m2-d2 denotes a date

ensure

result is number of days by which

y1-m1-d1 is earlier than y2-m2-d2 }

Page 30: Formal techniques for getting software right: some old ideas and some new tools

‘Defensive’ programming

Always check parameters.

Problem, what if there is nothing to be done in case of error?

What is Sqrt(-16.0)? (real square-root, not complex)

What do you think of this (real) example?function Sqrt(x: real): real;

begin

if x < 0 then x := -x:

calculate square-root of x

Page 31: Formal techniques for getting software right: some old ideas and some new tools

DaysEarlier: ‘defensive’ version

function DaysEarlier(y1, m1, d1, y2, m2, d2: integer); integer;

{ return number of days by which

y1-m1-d1 is earlier than y2-m2-d2

or -999 if either or both not a valid date}

days := DaysEarlier(2012, 11, 02, 1943, 06, 31);

if days = -999 then writeln(‘One or both dates not valid’)

else writeln(‘days earlier is’, days);

Says ‘One or both dates not valid’! What is wrong?

Page 32: Formal techniques for getting software right: some old ideas and some new tools

Problem

days := DaysEarlier(2012, 05, 21, 2010, 02, 07);

if days = -999 then writeln(‘One or both dates not valid’)

else writeln(‘days earlier is’, days);

Says ‘One or both dates not valid’! What is wrong?

True story: Took three weeks to solve!

Page 33: Formal techniques for getting software right: some old ideas and some new tools

Java Modeling Language: JML

The ideas of Design by Contract and Eiffel are extended and made available for Java in

JML: Java Modeling Language

http://www.eecs.ucf.edu/~leavens/JML/

Lots of @ and \.

Includes quantifiers (, , , …)

Following examples are from:An overview of JML tools and applications

Lilian Burdy1, Yoonsik Cheon2, David R. Cok3, Michael D. Ernst4, Joseph R. Kiniry5, Gary T.Leavens6?, K. Rustan M. Leino7, Erik Poll51

Software Tools for Technology Transfer

Page 34: Formal techniques for getting software right: some old ideas and some new tools

JML: Special comments

JML is simply extending Java

uses special comments with lots of @, \

Keywords are

requires

ensures

\ result

\ old(x)

\ forall

Page 35: Formal techniques for getting software right: some old ideas and some new tools

JML example

/*@ requires amount >= 0;

@ assignable balance;

@ ensures balance == \old(balance) - amount

@ && \result == balance;

@*/

int debit(int amount) throws PurseException {

if (amount <= balance) {

balance -= amount;

return balance;

} else { throw new PurseException("overdrawn by " + amount);

}

}

Page 36: Formal techniques for getting software right: some old ideas and some new tools

JML quantifiers

/*@ requires 0 < mb && 0 <= b && b <= mb

@ && p != null && p.length == 4

@ && (\forall int i; 0 <= i && i < 4;

@ 0 <= p[i] && p[i] <= 9);

@ assignable MAX_BALANCE, balance, pin;

@ ensures MAX_BALANCE == mb && balance == b

@ && (\forall int i; 0 <= i && i < 4; p[i] == pin[i]);

@*/

Purse(int mb, int b, byte[] p) {

MAX_BALANCE = mb; balance = b; pin = (byte[]) p.clone();

‘Symbol abuse’?

Page 37: Formal techniques for getting software right: some old ideas and some new tools

Provers

Showing that assertions (requires, ensures ..) are true when program runs only demonstrates correctness for chosen test cases.

(Dijkstra famously observed; testing can show presence of errors, not their absence’)

Much better is to use software tools called provers, that reason about whether program matches its specification.

These exist for JML and for Spec#.

Page 38: Formal techniques for getting software right: some old ideas and some new tools

Spec#

‘Spec sharp’: based on the C# programming language.

http://research.microsoft.com/en-us/projects/specsharp/

Similar to JML, but neater syntax, since a new language based on C#; not just C# with special comments.

Spec# is available (free of charge) as a plug-in to Visual Studio™.

Page 39: Formal techniques for getting software right: some old ideas and some new tools

Spec# keywords

requires

ensures

result

old(x)

forall

exists

Page 40: Formal techniques for getting software right: some old ideas and some new tools

Simple example of Spec#

int max(int x, int y)

ensures (result == x && x >= y) || (result == y && y >= x);

{

if (x >= y) return x;

else return y;

}

Note: no requires, because no precondition.

Is this correct?

What about when x == y?

Page 41: Formal techniques for getting software right: some old ideas and some new tools

Easy way to use provers

http://rise4fun.com/specsharp/

Page 42: Formal techniques for getting software right: some old ideas and some new tools

What if it is wrong?

int max(int x, int y)

ensures (result == x && x > y) || (result == y && y > x);

{

if (x >= y) return x;

else return y;

}

What about when x == y?

Page 43: Formal techniques for getting software right: some old ideas and some new tools

Result from Spec#

Unsatisfied postcondition

Page 44: Formal techniques for getting software right: some old ideas and some new tools

Example with a loop: DivMod

void DivMod(int x, int y, ref int q, ref int r)

requires x >= 0 && y > 0;

ensures x == q*y + r && 0 <= r && r < y;

{ r= x; q= 0;

while (r >= y)

invariant x == q*y + r && 0 <= r;

{

r= r - y; q= q + 1;

}

}

invariant will be true at this point every time round.

Page 45: Formal techniques for getting software right: some old ideas and some new tools

Spec# happy

Page 46: Formal techniques for getting software right: some old ideas and some new tools

Quantifiers and ranges in Spec#

forall

exists

Ranges

int i in (m..n) means: all i m <= i <= n

int i in (m:n) means: all i m <= i < n

Second form useful; saves lots of -1’s

Page 47: Formal techniques for getting software right: some old ideas and some new tools

What do you think of this?

static int Min(int[] a)

requires a != null && a.Length != 0;

ensures a == old(a) && (forall {int i in (0:a.Length); result <= a[i]};

{ int min = 0;

for (int j = 0; j < a.Length; j++)

invariant forall {int i in (0:j); min <= a[i]};

if (a[j] < min)

min = a[j];

return min;

}

Page 48: Formal techniques for getting software right: some old ideas and some new tools

Example with quantifiers

int First(int[] a, int x)

ensures forall{k in (0: result); a[k] != x} &&

(result == -1 || 0 <= result && result < a.Length && a[result] == x);

{

int i;

i = 0;

while (i != a.Length && a[i] != x)

invariant 0 <= i && i <= a.Length && forall{k in (0: i); a[k] != x};

{

i++;

}

if (i == a.Length) return -1; else return i;

}

Page 49: Formal techniques for getting software right: some old ideas and some new tools

Further useful feature of Spec#

What does this do?

float AverageLength(string [ ] s)

{

int sum = 0;

for (int i = 0; i < s.Length; i++)

sum += s[i].Length;

return float(sum)/s.Length;

}

What is it precondition?

Page 50: Formal techniques for getting software right: some old ideas and some new tools

AverageLength

Returns average length of the strings in array of strings s.

Precondition? s.Length > 0float AverageLength(string [] s)

requires s.Length > 0;

{ int sum = 0;

for (int i = 0; i < s.Length; i++)

sum += s[i].Length;

return float(sum)/s.Length;

}

Anything else?

Page 51: Formal techniques for getting software right: some old ideas and some new tools

Precondition of AverageLength

s.Length > 0

But arrays implemented by pointers in Java, C# …

So we need to add

s != null

Page 52: Formal techniques for getting software right: some old ideas and some new tools

s != null

float AverageLength(string [] s)

requires s != null &&

s.Length > 0;

{ int sum = 0;

for (int i = 0; i < s.Length; i++)

sum += s[i].Length;

return float(sum)/s.Length;

}

Page 53: Formal techniques for getting software right: some old ideas and some new tools

s[j] != null

But strings implemented by pointers in Java, C# …

So we need to add

s[i] != null for all the indexes of s

forall{int j in (0: s.Length); s[j] != null};

Page 54: Formal techniques for getting software right: some old ideas and some new tools

s[j] != null

float AverageLength(string [] s)

requires

s != null &&

forall{int j in (0: s.Length); s[j] != null} &&

s.Length > 0;

{ int sum = 0;

for (int i = 0; i < s.Length; i++)

sum += s[i].Length;

return float(sum)/s.Length;

}

Page 55: Formal techniques for getting software right: some old ideas and some new tools

Non-null pointers

Very often we require a pointer not to be null.

Easy to forget;

Untidy to check or to add as precondition.

Special syntax in Spec# !

float AverageLength(string ! [] ! s)

requires s.Length > 0;

! means must be non-null type.

Enforced by compiler.

Page 56: Formal techniques for getting software right: some old ideas and some new tools

Proving termination

What we have shown so far is partial correctness.; program satisfies its specification, if it terminates.

We prove termination by finding a relationship between the variables on a loop that is initially non-negative and that is strictly reduced by each iteration.

No support for this in Spec#, but can make our own by introducing auxiliary variables to hold value of bound.

Page 57: Formal techniques for getting software right: some old ideas and some new tools

Example of bound in Spec#

void DivMod(int x, int y, ref int q, ref int r)

requires x >= 0 && y > 0;

ensures x == q*y + r && 0 <= r && r < y;

{ int bound; r= x; q= 0;

while (r >= y)

invariant x == q*y + r && 0 <= r &&

bound = r && bound >= 0;

{ r= r - y; q= q + 1;

assert(r < bound);

}

}

Page 58: Formal techniques for getting software right: some old ideas and some new tools

Unresolved so far (by me, at least)…

assert does run-time check. How to check termination without resorting to run-time check.

How to specify processes that modify a structure (such as sorting). Need to be able to use old (or equivalent) inside the body (old only useable in postcondition).

Page 59: Formal techniques for getting software right: some old ideas and some new tools

Summary

Techniques are not new – 1960’s

Not widely known outside universities.

Not even known to nuclear-physicist researchers in England.

Now taken seriously by Microsoft in Spec# and similar projects and in Eiffel and JML.

Advantages:

Can get programs right much earlier in development hence much less time in debugging.

Reduced danger of erroneous programs.

Page 60: Formal techniques for getting software right: some old ideas and some new tools

Current use

• JKU Linz course: Romanian-speaking Hungarian students.

• Politechnika Warszawska• P00401 Formal Software Engineering• U08186 Advanced Object-Oriented Programming

Page 61: Formal techniques for getting software right: some old ideas and some new tools

Contact information

www.brookes.ac.uk

David Lightfoot

Email: [email protected]

Telephone: +44 18 65 48 45 39

School of Technology

Oxford Brookes University

Wheatley Campus

Oxford OX33 1HX

United Kingdom

Page 62: Formal techniques for getting software right: some old ideas and some new tools

Dziękuję!