Rigorous Software Development CSCI-GA 3033-011 Instructor: Thomas Wies Spring 2012 Lecture 9.

Slides:



Advertisements
Similar presentations
1 Lecture 5 Towards a Verifying Compiler: Multithreading Wolfram Schulte Microsoft Research Formal Methods 2006 Race Conditions, Locks, Deadlocks, Invariants,
Advertisements

Joint work with Mike Barnett, Robert DeLine, Manuel Fahndrich, and Wolfram Schulte Verifying invariants in object-oriented programs K. Rustan M. Leino.
Copyright © 2006 The McGraw-Hill Companies, Inc. Programming Languages 2nd edition Tucker and Noonan Chapter 18 Program Correctness To treat programming.
Object Invariants in Specification and Verification K. Rustan M. Leino Microsoft Research, Redmond, WA Joint work with: Mike Barnett, Ádám Darvas, Manuel.
Writing specifications for object-oriented programs K. Rustan M. Leino Microsoft Research, Redmond, WA, USA 21 Jan 2005 Invited talk, AIOOL 2005 Paris,
Technologies for finding errors in object-oriented software K. Rustan M. Leino Microsoft Research, Redmond, WA Lecture 3 Summer school on Formal Models.
Automated Theorem Proving Lecture 1. Program verification is undecidable! Given program P and specification S, does P satisfy S?
Lecture 4 Towards a Verifying Compiler: Data Abstraction Wolfram Schulte Microsoft Research Formal Methods 2006 Purity, Model fields, Inconsistency _____________.
Challenges in increasing tool support for programming K. Rustan M. Leino Microsoft Research, Redmond, WA, USA 23 Sep 2004 ICTAC Guiyang, Guizhou, PRC joint.
Rigorous Software Development CSCI-GA Instructor: Thomas Wies Spring 2013 Lecture 5 Disclaimer. These notes are derived from notes originally.
Rigorous Software Development CSCI-GA Instructor: Thomas Wies Spring 2012 Lecture 6 Disclaimer. These notes are derived from notes originally.
Rigorous Software Development CSCI-GA Instructor: Thomas Wies Spring 2012 Lecture 8.
Identity and Equality Based on material by Michael Ernst, University of Washington.
Verification of Multithreaded Object- Oriented Programs with Invariants Bart Jacobs, K. Rustan M. Leino, Wolfram Schulte.
Rigorous Software Development CSCI-GA Instructor: Thomas Wies Spring 2012 Lecture 11.
A simple sequential reasoning approach for sound modular verification of mainstream multithreaded programs Wolfram Schulte & Bart Jacobs Microsoft Research.
Composition CMSC 202. Code Reuse Effective software development relies on reusing existing code. Code reuse must be more than just copying code and changing.
Binary Trees. DCS – SWC 2 Binary Trees Sets and Maps in Java are also available in tree-based implementations A Tree is – in this context – a data structure.
Rigorous Software Development CSCI-GA Instructor: Thomas Wies Spring 2012 Lecture 13.
Copyright © 2006 The McGraw-Hill Companies, Inc. Programming Languages 2nd edition Tucker and Noonan Chapter 18 Program Correctness To treat programming.
JML and Class Specifications Class invariant JML definitions Queue example Running JML in Eclipse.
Chair of Software Engineering 1 Introduction to Programming Bertrand Meyer Exercise Session 6 7 October 2008.
ECI 2007: Specification and Verification of Object-Oriented Programs Lecture 3 Courtesy: K. Rustan M. Leino and Wolfram Schulte.
Eiffel Language and Design by Contract Contract –An agreement between the client and the supplier Characteristics –Expects some benefits and is prepared.
(c) University of Washingtonhashing-1 CSC 143 Java Hashing Set Implementation via Hashing.
Software Engineering Prof. Dr. Bertrand Meyer March 2007 – June 2007 Chair of Software Engineering Static program checking and verification Slides: Based.
1 Abstraction  Identify important aspects and ignore the details  Permeates software development programming languages are abstractions built on hardware.
Cs205: engineering software university of virginia fall 2006 Data Abstraction David Evans
Announcements  I will discuss the labtest and the written test #2 common mistakes, solution, etc. in the next class  not today as I am still waiting.
AITI Lecture 20 Trees, Binary Search Trees Adapted from MIT Course 1.00 Spring 2003 Lecture 28 and Tutorial Note 10 (Teachers: Please do not erase the.
CS212: Object Oriented Analysis and Design Lecture 6: Friends, Constructor and destructors.
A Singleton Puzzle: What is Printed? 1 public class Elvis { public static final Elvis INSTANCE = new Elvis(); private final int beltSize; private static.
Design by Contract in Java Concept and Comparison.
More About Classes Ranga Rodrigo. Information hiding. Copying objects.
Synthesis, Analysis, and Verification Lecture 05b Lectures: Viktor Kuncak Dynamic Allocation Linked Structures and Their Properties WS1S.
Synthesis, Analysis, and Verification Lecture 05a Lectures: Viktor Kuncak Programs with Data Structures: Assertions for Accesses. Dynamic Allocation.
Today’s Agenda  Quick Review  Continue on JML Formal Methods in Software Engineering1.
Internet Software Development Controlling Threads Paul J Krause.
CIS 771: Software Specifications Lecture 18: Specifying and Checking Partial Properties of Java Code Copyright , Matt Dwyer, John Hatcliff, and.
Verification of Programs with Inspector Methods Bart Jacobs and Frank Piessens Dept. CS, K.U.Leuven, Belgium.
CS 61B Data Structures and Programming Methodology July 3, 2008 David Sun.
CIS* Quiz 2. For a large array, and in the worst case, selection sort is faster than insertion sort. False Both selection sort and insertion sort.
A Universe-Type-Based Verification Technique for Mutable Static Fields and Methods Alexander J Summers Sophia Drossopoulou Imperial College London Peter.
(c) University of Washington15-1 CSC 143 Java List Implementation via Arrays Reading: 13.
“Never doubt that a small group of thoughtful, committed people can change the world. Indeed, it is the only thing that ever has.” – Margaret Meade Thought.
(c) University of Washington16-1 CSC 143 Java Linked Lists Reading: Ch. 20.
(c) University of Washington16-1 CSC 143 Java Lists via Links Reading: Ch. 23.
Application development with Java Lecture 21. Inheritance Subclasses Overriding Object class.
PROGRAMMING PRE- AND POSTCONDITIONS, INVARIANTS AND METHOD CONTRACTS B MODULE 2: SOFTWARE SYSTEMS 13 NOVEMBER 2013.
1 Verification of object-oriented programs with invariants Mike Barnett, Robert DeLine, Manuel Fahndrich, K. Rustan M. Leino, Wolfram Schulte ECOOP 2003.
CSE 501N Fall ‘09 10: Introduction to Collections and Linked Lists 29 September 2009 Nick Leidenfrost.
 Description of Inheritance  Base Class Object  Subclass, Subtype, and Substitutability  Forms of Inheritance  Modifiers and Inheritance  The Benefits.
David Evans CS201J: Engineering Software University of Virginia Computer Science Lecture 7: A Tale of Two Graphs (and.
David Evans CS201J: Engineering Software University of Virginia Computer Science Lecture 5: Implementing Data Abstractions.
Reasoning and Design (and Assertions). How to Design Your Code The hard way: Just start coding. When something doesn’t work, code some more! The easier.
Section 2.3 Array-Based StringLog ADT Implementation.
Object Invariants in Dynamic Contexts K.R.M. Leino and P. Muller : Objects and Aspects Presented by Jonathan Aldrich.
Extended Static Checking for Java
Section 2.6 Linked List StringLog ADT Implementation
Accessible Formal Methods A Study of the Java Modeling Language
slides created by Ethan Apter
Hoare-style program verification
slides created by Ethan Apter
Lecture 4: Data Abstraction CS201j: Engineering Software
CIS 199 Final Review.
CSC 143 Java Linked Lists.
Java Modeling Language (JML)
slides created by Ethan Apter and Marty Stepp
Programming Languages 2nd edition Tucker and Noonan
Presentation transcript:

Rigorous Software Development CSCI-GA Instructor: Thomas Wies Spring 2012 Lecture 9

Class Invariants Class invariants are properties that must hold at the entry and exit point of every method They often express properties about the consistency of the internal representation of an object. They are typically transparent to clients of an object. They are sometimes also called object invariants or instance invariants.

The Problem with Class Invariants There are some problems with class invariants: Ownership: invariants can depend on fields of other objects. – For example, the invariant of List accesses Node fields. Callback: invariants can be temporarily violated. – While the invariant is violated, we call a different method that calls back to the same object. Atomicity: invariants can be temporarily violated. – While the invariant is violated, another thread accesses object.

Invariants May Depend on Other Objects class Node { Node prev, next; } class List { private Node first; private ghost JMLObjectSet invariant (\forall Node n; nodes.has(n); n.prev.next == n && n.next.prev == public void add() { Node newnode = new Node(); newnode.prev = first.prev; newnode.next = first; first.prev.next = newnode; first.prev = newnode; set nodes = nodes.insert(newnode); }

Invariants May Depend on Other Objects List Node first Node next prev Node next prev Node next prev next List Node first Node next prev n.next = val Invariants must be protected from unsolicitous updates of dependent fields.

The Owner-As-Modifier Property JML supports a type system for checking the owner-as-modifier property, when invoked as jmlc --universes. The underlying type system is called Universes: The class Object has a ghost field owner. Fields can be declared as rep, peer, readonly. – rep Object x adds an implicit invariant (or requires) x.owner = this. – peer Object x adds an implicit invariant (or requires) x.owner = this.owner. – readonly Object x does not restrict owner, but does not allow modifications of x. The new operation supports rep and peer : – new sets owner field of new node to this. – new sets owner field of new node to this.owner.

List with Universes Type System class Node { Node prev, next; } class List { private Node first; private ghost JMLObjectSet invariant (\forall Node n; nodes.has(n); n.prev.next == n && n.next.prev == n && n.owner == public void add() { Node newnode = new Node(); newnode.prev = first.prev; newnode.next = first; first.prev.next = newnode; first.prev = newnode; set nodes = nodes.insert(newnode); }

Modification only by Owner All write accesses to a field of an object obj are in a method of the owner of obj or in a method of an object having the same owner as the object that was invoked (directly or indirectly) by the owner of obj. Invariants that only depend on fields of owned objects can only be invalidated by the owner or methods that the owner invokes.

Modification only by Owner List Node first Node next prev Node next prev Node next prev next List Node first Node next prev n.next = val peer rep peer rep Universes type system ensures that all write accesses of dependent fields go through the owner.

Limitations of Universes Type System The Universes type system can solve many ownership related problems. but It’s granularity is often too coarse. What happens if invariants are temporarily violated?

Temporarily Violating Invariants public class Container { int[] content; int size; invariant 0 <= size && size <= public void add(int v) { /* 1 */ size++; /* 2 */ if (size > content.length) { newContent = new int[2*size+1];... content = newContent; }... /* 3 */ } When do Invariants Hold? Before a public method is called. /* 1 */ After a public method returns. /* 3 */ However, it may be violated in between. /* 2 */

Calls to Private Methods public class Container { int[] content; int size; invariant 0 <= size && size <= private void growContent() {... content = newContent; } public void add(int v) { /* invariant should hold */ size++; /* invariant may be violated */ if (size > content.length) growContent();... /* invariant should hold, again */ } Sometimes an invariant may not hold before a private method call. JML provides the annotation for this.

Calls to Methods of Other Classes public class Container { int[] content; int size; invariant 0 <= size && size <= private void growContent() { /* invariant may be violated */ newContent = new int[2*size+1]; System.arraycopy(content, 0, newContent, 0, content.length); content = newContent; }... } The invariant still needs not to hold, when other methods are called, because there is the callback problem.

The Callback Problem public class Log { public void log(String p) { logfile.write("Log: “ + p + " list is “ + Global.theList); } public class Container { int[] content; int size; invariant 0 <= size && size <= public void add(int v) { /* invariant should hold */ size++; /* invariant may be violated */ if (size > content.length) { Logger.log("growing array.");... } public String toString() { /* invariant should hold */... } implicit call to method toString

The Callback Problem A method of a different class can be called while an invariant is violated. This method may call a method of the first class. Who has to ensure that the invariant holds? – jmlrac complains that the invariant does not hold. – ESC/Java checks that most invariants hold at every method call. – But not in every case; this may lead to unsoundness.

Adding Ghost Fields to Guard Invariants Idea of David A. Naumann and Mike Barnett: Make the places where an invariant does not hold explicit. Add a ghost field packed that indicates wether the invariant should hold. Before modifying an object set this field to false. When modification is complete, set it back to true. The following invariant should always hold: packed ==> invariants of object The caller has to ensure that all objects he uses are packed.

The pack/unpack Mechanism public ghost boolean packed; private invariant packed ==> (size >= 0 && size <= content.length); requires ensures public void add(int v) { unpack this; size++;... pack this; } The pre- and post-conditions explicitly state that invariant holds. unpack this is an abbreviation for: assert this.packed; set this.packed = false; pack this is an abbrevation for: assert !this.packed; assert /*invariant of this holds*/; set this.packed = true;

The pack/unpack Mechanism An object must be unpacked before its fields may be modified. The invariant has to hold only while object is packed. The invariant may only depend on fields of the object. object unpack pack packed == true packed == false invariants hold invariants may be broken object.f = val

Static Checking with pack/unpack Static Checking with packed ghost field: Fields may only be modified if packed is false. For each pack operation check that invariants hold again. Thus packed ==> invariants holds for all states.

Example: Tree Data Structure class TreeNode { int key, value; TreeNode left, right; invariant left != null ==> left.key <= key &&...; invariant right != null ==> right.key >= key &&...; public void add(int k, int v) { if (k < key) { if (left == null) left = new TreeNode(k, v); else left.add(n); } else... }

Adding the packed Ghost Field class TreeNode { int key, value; TreeNode left, right; public ghost boolean packed = false; invariant packed ==> left != null ==> left.key <= key &&...; invariant packed ==> right != null ==> right.key >= key &&...; requires packed; ensures packed; public void add(int k, int v) { // unpack this if (k < key) {... } else... // pack this }

Runing ESC/Java > escj -q TreeNode.java TreeNode.java:40: Warning: Precondition possibly not established (Pre) left.add(n); ^ Associated declaration is "TreeNode.java", line 20, col 8: requires packed; The nodes left and right must also be packed !

Adding the Additional Invariants class TreeNode { int key, value; TreeNode left, right; public ghost boolean packed = false; invariant packed ==> left != null left.packed && left.key <= key invariant packed ==> (right != null right.packed && right.key >= key requires packed; ensures packed; public void add(int v, int k) {... }

Adding Ownership There are still problems: The invariants also depend on fields of left and right. In particular the fields left.key and left.packed. – Can unpack this violate the invariant of another TreeNode ? – Can insertion of a new node break the sortedness of the overall tree? Solution: Use the ownership principle.

Ownership and pack/unpack The owner must be unpacked before an owned object can be unpacked. The invariant of owner may depend on owned objects. owner unpack owner owner.packed == true left.pacled == true owner.f = val left.f = val left right left right owner left right pack owner owner.packed == false left.pacled == true owner.packed == false left.pacled == false left.f = val unpack left pack left

Ownership and pack/unpack How does pack/unpack work with ownership? To modify an object, you must unpack it first. To unpack an object, you must first unpack the owner. To pack the owner again, its invariants must hold. unpack obj is an abbreviation for: assert obj.packed; assert obj.owner == null || !obj.owner.packed; set obj.packed = false; pack obj ensures that its owned classes are packed. assert !obj.packed; assert left != null ==> (left.owner == this && left.packed); assert right != null ==> (right.owner == this && right.packed); assert /* other invariants of obj hold*/; set obj.packed = true;

Adding Ownership class TreeNode { int key, value; TreeNode left, right; public ghost boolean packed = false; invariant packed ==> (left != null left.owner == this && left.packed && left.key <= invariant packed ==> (right != null right.owner == this && right.packed && right.key >= requires packed; requires owner == null || !owner.packed; ensures packed; public void add(int k, int v) {... } }

Limitations of Ownership Discipline The ownership discipline has a few restrictions. An object invariant can only depend on fields of (transitively) owned objects. An object can have at most one owner. A field may only be changed by the owner, or if the owner is unpacked. Sometimes this is too restrictive!

Friendship Friendship is an orthogonal discipline for dealing with invariants that depend on other objects: Objects can be friends and granters. An invariant of a friend can depend on the fields of a granter. The friend must define update guards for the fields of the granter it depends on. The granter has a list of friends that depend on its fields. A field of a granter may be changed only if the update guards of all friends holds.

Friendship Friendship is not symmetric. The allies are: Granter G that gives the right to depend on one of its fields. class G { int f; friend C reads f; } Friend C whose invariant depends on a field. class C { invariant packed ==>... g.deps.has(this) g.f guard g.f := val } Every class that changes a field f of G has to check the guards of all of G ’s friends that depend on f.

Update Guards and Invariants class FriendClass { invariant packed ==> friendInvariant(granter.field) guard granter.field := val updateGuardForField(granter, } The update guard must guarantee that the invariant is not invalidated: friends.packed && friendInvariant(granter.field) && updateGuardForField(granter, val) ==> friendInvariant(val)

Updating Granted Fields A friend's invariant can depend on granted fields. Updates of granted fields are checked against update guards. A granter can have many friends. Update guards of all current friends must be checked. The friend objects can be packed or unpacked. Update guard is not checked for unpacked friends. friend1granterfriend2 deps granter.f = val guard

Friendship Example: HashMap class Object { int hashCode; friend Map reads hashCode; ghost JMLObjectSet deps; } class Map { JMLObjectSet buckets[]; invariant (\forall int i ; 0 <= i && i < (\forall Object o; buckets[i].has(o); o.deps.has(this) Math.abs(o.hashCode % buckets.length) == guard obj.hashCode := val val % buckets.length == obj.hashCode % }

static class Node { Node next, prev; Object value; friend Node reads next, prev, deps guard obj.next = val by obj != prev; guard obj.prev = val by obj != next; invariant packed ==> next != null && prev != null && deps.equals(new JMLObjectSet().insert(next).insert(prev)) && next.deps.has(this) && next.prev == this && prev.deps.has(this) && prev.next == this); */ } Friendship Example: Doubly-Linked Lists

static class Node {... requires n.prev == n.next == n; public void Node n) { unpack n; unpack this; unpack this.prev; n.prev = this.prev; n.next = this; this.prev.next = n; this.prev = n; set n.deps new set this.deps = this.deps.remove(prev).add(n); set prev.deps = prev.deps.remove(this).add(n); pack this.prev; pack this; pack n; }

What May Appear in an Invariant? Only the following field accesses are allowed in an invariant: A field of the current class: this.field for all fields. A field of a (transitively) owned class: x.field if x.owner...owner == this can be proved. A field of a granter class: x.field if x.deps.has(this) can be proved.

Why Is this Discipline Sound? We need to show that the following invariant holds at all times for each instance this : this.packed ==> this.invariant A field update obj.f = val can change the truth of the invariant if: obj == this is the current instance: Then this is unpacked, formula holds trivially. obj.owner...owner == this ( obj is an owned instance of this ): Then obj is unpacked, hence this must also be unpacked. The formula holds trivially. obj.deps.has(this) ( f is a field of a granter of this ): Then the update guard this.guard(f, val) is true. If this.packed is true, the invariant held before. Hence it must hold afterwards.