1 / 62

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: dlightfoot@brookes.ac.uk Department of Computing and Communication Technologies Oxford Brookes University England. Abstract.

deidra
Download Presentation

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

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. Formal techniques for getting software right: some old ideas and some new tools • Applied Formal Methods Research Group • 2012-11-02 • David Lightfoot: dlightfoot@brookes.ac.uk • Department of Computing and Communication Technologies • Oxford Brookes University • England

  2. 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.

  3. 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?

  4. 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?

  5. 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?

  6. 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)

  7. 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

  8. 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 …

  9. Not a new idea: Professor Sir Tony Hoare Formerly Head of Programming Research Group (PRG), Oxford University, England Senior 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.

  10. ‘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’

  11. 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

  12. 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

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

  14. 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.

  15. 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.

  16. 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.

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

  18. 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) isP[var/exp ] • Also famous for P and V and Travelling-Salesman problem, …

  19. 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(); ?

  20. 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…

  21. 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)

  22. 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

  23. integerSqrt in Eiffel integerSqrt (x: INTEGER) : INTEGER -- return the integer square-root of non-negative x require non-negative_x: x >= 0 • ensure • result is floor of square-root of x: • result*result <= x and x < (result+1)*(result+1)

  24. 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.

  25. 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.

  26. 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;

  27. 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'.

  28. 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}

  29. 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 }

  30. ‘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 • …

  31. 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?

  32. 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!

  33. 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

  34. JML: Special comments • JML is simply extending Java • uses special comments with lots of @, \ • Keywords are • requires • ensures • \ result • \ old(x) • \ forall • …

  35. 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); • } • }

  36. 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’?

  37. 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#.

  38. 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™.

  39. Spec# keywords • requires • ensures • result • old(x) • forall • exists • …

  40. 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?

  41. Easy way to use provers • http://rise4fun.com/specsharp/

  42. 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?

  43. Result from Spec# Unsatisfied postcondition

  44. 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.

  45. Spec# happy

  46. 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

  47. 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; • }

  48. 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; • }

  49. Further useful feature of Spec# • What does this do? • float AverageLength(string [ ] s) • { • int sum = 0; • for (inti = 0; i < s.Length; i++) • sum += s[i].Length; • return float(sum)/s.Length; • } • What is it precondition?

  50. AverageLength • Returns average length of the strings in array of strings s. • Precondition? s.Length > 0 • float AverageLength(string [] s) • requires s.Length > 0; • { int sum = 0; • for (inti = 0; i < s.Length; i++) • sum += s[i].Length; • return float(sum)/s.Length; • } • Anything else?

More Related