310 likes | 487 Views
Verification of object-oriented programs with invariants. Mike Barnett, Robert DeLine, Manuel Fahndrich, K. Rustan M. Leino, Wolfram Schulte ECOOP 2003 workshop on Formal Techniques for Java-like Programs. Encapsulation Seminar TAU 2005 Presented by Yossi Peery. Agenda. Introduction
E N D
Verification of object-oriented programswith invariants Mike Barnett, Robert DeLine, Manuel Fahndrich, K. Rustan M. Leino, Wolfram Schulte ECOOP 2003 workshop on Formal Techniques for Java-like Programs Encapsulation Seminar TAU 2005 Presented by Yossi Peery
Agenda • Introduction • Motivation and Background • Object Invariants and Information Hiding • Solution • Basic Methodology Concepts • Adding Components and Subclasses • Modifies Clause and Dynamic Dispatching • Examples • Conclusion
Why Use Object Invariants • Definition: “A relation on an object’s data that the programmer intends for to hold” • Detect and prevent • Data corruption errors • Misuse of the object data • Formal methods allow automatic static verification of program invariants
Background • Hoare’s 1972 “Proof of correctness of data representations” • Eiffel • Pioneer Design by Contract technique • Dynamically checks invariants at run-time • Peter Muller 2001 • An OO language providing useful guarantees about when object invariants hold • Uses “Universe Type System” as an ownership model • Object invariants modeled by a boolean function on the object’s data
Reentrancy Problem public method P (…) { … M (); … }
Invariant Misconception • General View: An invariant is an implicit post-condition on every constructor and an implicit pre- and post-condition on every public method • Misconception: • Callers of an object’s methods do not need to establish the implicit pre-condition of the invariant. • It is sufficient to restrict modifications of the invariant to methods of an object and establish it before the method ends
Explicit Invariant Condition • It will not be possible to call M from a function P that doesn’t ensure its invariant. Or, • It will not be possible to call a function P that ensure the invariant from the middle of M
Problem of Information Hiding • Invariants are conditions on the internal representation of objects • Explicit pre- and post-conditions are a breach of good information hiding • Conflict between revealing implementation details and the need for clients to know whether the object invariant holds • Same problem exists for modifies clause
Basic Methodology Concept • Provide an explicit representation of when object invariants are known to hold • Add special public field st to every object. o.st = Invalid o is invalid o.st = Valid o is valid • An object’s invariant holds whenever the object is valid • Restrictions • st can appear only in routine specifications • st can be modified only by special new statements: pack & unpack • Objects are allocated with o.st = Invalid
Basic Methodology Concept • InvT(o) : predicate to indicate that the invariant of object o of class T holds. Using class T from previous example:
Restrictions and Validity • Object field updates can break invariant: • Field update statements: o.f := E • Permitted only where o.st = Invalid • InvT(o) can depend only on internal fields of o • If the above restrictions hold then the following is a program invariant: where o ranges over non-null objects of type T • Proof by induction over structure of program statements
Components • Objects are usually built in a hierarchy of layered abstractions • A “Buffered Input Stream” can be implemented in terms of a cache and a file reader objects • Program correctness may depend on relations between fields of an objects and fields of its components • Need to expend previous restrictions
Components • If t.f = u then update of u.g breaks T’s invariant • Need to make sure that: u.st = Invalid => t.st = Invalid t.st = Valid => u.st = Committed
Ownership • Committed state indicates Ownership • If t.f.st = Commited then t owns t.f • Creates hierarchy of owned objects • Use repmodifier to indicate that a field is a component: private rep f : U; • Object invariants can now depend on this.f0.f1.f2. … .g where fi are declared with the repmodifier
Components st : { Invalid , Valid, Committed} CompT(o) = { o.f : f is a rep field in T }
Components • Program Invariant: • Unique Ownership: • Ownership Transfer:
Subclasses • Object divided into class frames • Each frame can be valid or invalid • possible subsets • Consider only nonempty prefixes • { object } • { object, A } • { object, A, B }
New Encoding • Instead of st: • Special field inv holdstype of most derived valid class • Special field committed is boolean indicating if object is committed committed = TRUE => inv = type(o) • New objects of type T should return from theconstructor as: inv = T & !commited • Field updates of subclass allowed if object is “sufficiently unpacked” • Invariants may contain fields of subclasses
New Encoding T extends S ois any subclass ofT
Soundness Theorem The following are program invariants (ranges over non-null objects; <: is the subclass relationship) Proof shows the conditions are maintained for all actions that extend the quantification range or change values of object fields
Modifies Clause • Model access to an object field by changes to the program heap: • Heap is a global 2 dimensional array indexed by object references and field names • Location if o.f is modeled by Heap[o,f] • Modifies Clause contains a set of heap locations the routine is allowed to modify • Routines are allowed to allocate new objects and modify their state • Special field alloc denotes allocated objects
Modifies Clause • Post-condition for modifies clause W: • Innovation: allow every routine to modify fields of commited objects: • Implementation Hiding • Use special expression E.{ T } • T = { class name, type(o) for object-valued expression o } • Denotes all regular fields of object E declared in class T and its super classes
Dynamic Dispatch • pack and unpack statements need to specify which type they are unpacking • Need to state the exact value of inv as a precondition • Limits use of dynamic dispatching • Innovation: • Use special expression: inv = 1 • For caller 1 means type(this) • For implementation in class T, 1 means T • How can this be sound?
Dynamic Dispatch • Soundness: • For declaration of dynamic dispatched method M, introduce a procedure named M with specification: inv = type(this) • For implementation of M in class T introduce a procedure M@T with specification: inv = T • Body of procedure M looks at type of this and calls corresponding procedure M@type(this) • Body of M@T is like that of method M in T except that any call for super class, super.M(…) is replaced with M@S • Every class must supply an implementation for every dynamically dispatched methoddeclared in the class or its super class • Extend 1 for the modifies clause: E.{1}
Examples • Can be used as a super class or a component • Subclass implementation can modify all regular fields of super class.
Examples Constructor must copy char array
Examples Constructor can capture the reader
Examples • Lexer can relinquish the underlying reader • Reader must be relinquished in an uncommitted state • Implementation leaves Lexer in an inconsistent state so that GetToken can no longer be invoked
Conclusions • Programmer must be aware at which points an object invariant can be relied upon • Presented method that provides programmers with a flexible and precise way to specify their intensions about object invariants • Ownership method allows a single valid owner per object at a time but doesn’t confine object aliasing and allows multiple read access • Methodology allows for both static verification and dynamic checking
Current Work • Spec # • Extension of C# with method contracts • Compiler and static verifier tools integrate with visual studio .NET • Boogie • Spec# static program verifier • WebSite http://research.microsoft.com/foundations