Date post: | 26-Mar-2015 |
Category: |
Documents |
Upload: | jake-mccann |
View: | 215 times |
Download: | 0 times |
Writing specifications for object-oriented programsK. Rustan M. LeinoMicrosoft Research, Redmond, WA, USA
21 Jan 2005Invited talk, AIOOL 2005Paris, France
joint work withMike Barnett, Robert DeLine, Manuel Fähndrich, Wolfram Schulte, Herman Venter,
Peter Müller, David A. Naumann,
Bor-Yuh Evan Chang, Bart Jacobs, Xinming Ou, and Qi Sun
Software engineering problem
Building and maintaining large systems that are correct
Using tools to program better• Specifications record design decisions
– bridge intent and code
• Tools amplify human effort– manage details– find inconsistencies– ensure quality
Spec#• Experimental mix of contracts and tool
support• Aimed at real programmers, real programs• Superset of C#
– non-null types– enhanced exception support– pre- and postconditions– object invariants
• Tool support– more type checking– compiler-emitted run-time checks– static program verification
Spec# demo
Basic architecture of a program verifier
verification conditiongenerator
theorem prover
verification condition
program with specifications
“correct” or list of errors
Spec# program verifier architecture
V.C. generator
automatictheorem prover
verification condition
Spec#
“correct” or list of errors
Spec# compiler
MSIL
translator
intermediate program representation
abstract interpreter
Spec# program verifier
Modular verification
• Don’t assume we have the entire program– for example, we want to be able to verify
a library without having access to its clients
• Verify a given portion of the program (e.g., a class) against its specifications, assuming that the rest of the program lives up to its specifications
• Analogous to separate compilation
Specification challenges
• Object invariants• Frame conditions (modifies clauses)• Class initialization and class
variables• Model fields• Delegates• …
Objects have invariants
class C {private int x;private int y;
public void M(){
int t := 100 / (y – x);x := x + 1;P(t);y := y + 1;
}
…}
division by zero
Pre/post are not enough
class C {private int x;private int y;public void M()
requires x < y;{
int t := 100 / (y – x);x := x + 1;P(t);y := y + 1;
}…
}
Object invariants
class C {private int x;private int y;invariant x < y;public void M(){
int t := 100 / (y – x);x := x + 1;P(t);y := y + 1;
}…
}
When do object invariants hold?
class C {private int x;private int y;invariant x < y;
public C() { x := 0; y := 1; }
public void M(){
int t := 100 / (y – x);x := x + 1;P(t);y := y + 1;
}…
}
invariant assumed to holdon entry to method
invariant checked to holdon exit from method
invariant checked to holdat end of constructor
invariant may betemporarily broken here
invariant is restored here
what if P calls back into M?
Object state: valid vs. mutable
• introduce a special object fieldst : { Mutable, Valid }
• idea: program invariant(o: C ・ o.st = Mutable InvC(o))
• field updates are allowed only for mutable objects:a field-update statement
o.f := E;has the precondition o.st = Mutable
holds at everyprogram point!
for any o: C, we writeInvC(o) ≡ o.x < o.y
class C {int x, y;invariant x < y;
pack/unpack statements
• st is changed by special statements pack and unpack
• pack o as C– check that InvC(o) holds
– then change o.st from Mutable to Valid
• unpack o from C– change o.st from Valid to Mutable
Example, with pack/unpack
class C {int x, y;invariant x < y;public void M(){
int t := 100 / (y – x);unpack this from C;x := x + 1;P(t);y := y + 1;pack this as C;
}…
}
invariant checkedto hold here
invariant may betemporarily broken here
Specifying methods and constructors
class C {int x, y;invariant x < y;public C()
ensures this.st = Valid;{
x := 0; y := 1;pack this as C;
}public void M()
requires this.st = Valid; {
int t := 100 / (y – x);unpack this from C;x := x + 1;P(t);y := y + 1;pack this as C;
}…
}
Note: if P calls back into M,then P must first make this valid
in order to satisfy M’s precondition,so no dangerous reentrancy can occur
Summary, so far
• invariant …• st : { Mutable, Valid }• pack, unpack• updates of o.f require o.st =
Mutable
• InvC(o) can mention only the fields of o
• (o: C ・ o.st = Mutable InvC(o))
Aggregate objectsclass Set {
Hashtable h;invariant …;
public void Add(Element e)requires this.st = Valid;
{unpack this from Set;h.Add(e, e);pack this as Set;
}…
}class Hashtable {
invariant …;public void Add(object key, object val)
requires this.st = Valid;…
}
how do we know his valid here?
Aggregate objectsclass Set {
Hashtable h;invariant …;
public void Add(Element e)requires this.st = Valid;
{unpack this from Set;h.Add(e, e);pack this as Set;
}public Hashtable Leak() { return h; }
}class Hashtable {
invariant …;public void Add(object key, object val)
requires this.st = Valid;…
}
how do we know his valid here?
Perhaps it isn’t!
void Violation(Set s)requires s.st = Valid;
{Hashtable g :=
s.Leak();unpack g from
Hashtable;g.x := …;s.Add(…);
}
Ownershipclass Set {
owned Hashtable h;invariant …;
public void Add(Element e)requires this.st = Valid;
{unpack this from Set;h.Add(e, e);pack this as Set;
}…
}class Hashtable {
invariant …;public void Add(object key, object val)
requires this.st = Valid;…
}
For any s: Set,• s uniquely owns s.h• validity of s implies validity of s.h
ownership of htemporarily
relinquished here
ownership of hre-obtained here
Object state: mutable, valid, committed
• st : { Mutable, Valid, Committed }
• program invariant(o: C ・ o.st = Mutable InvC(o))
• and for every owned field f(o: C ・ o.st = Mutable o.f.st =
Committed)
• pack o as C– check that InvC(o) holds,– check that o.f.st = Valid,– then change o.f.st from Valid to Committed– and change o.st from Mutable to Valid
• unpack o from C– change o.st from Valid to Mutable, and– change o.f.st from Committed to Valid
“Committed” means“valid and owned”
class C { owned T f; …
for every owned field f
Object states: a picture of the heap
Mutable
Valid
Committed
s: Set
Hashtable
ownershiph
unpack s from Set
Object states: a picture of the heap
Mutable
Valid
Committed
s: Set
Hashtable
ownershiph
unpack s from Set
Object states: a picture of the heap
Mutable
Valid
Committed
s: Set
Hashtable
ownershiph
pack s as Set
Object states: a picture of the heap
Mutable
Valid
Committed
s: Set
Hashtable
ownershiph
pack s as Set
Summary of object invariants
• invariant …• owned T f;• st : { Mutable, Valid, Committed }• pack, unpack• updates of o.f require o.st = Mutable• InvC(o) can mention only the fields of o
and the fields of owned fields– example: invariant this.n = this.h.Count;
• (o: C ・ o.st = Mutable InvC(o))
• (o: C ・ o.st = Mutable o.f.st = Committed)
Frame conditions
• To be useful to the caller, a postcondition must say what goes unchanged– ensures x = old(x) y = old(y) …
• A modifies clause says what is allowed to change, implicitly indicating what goes unchanged– modifies z
What do modifies clauses mean?
modifies M;=
modifies Heap;ensures
(o,f •Heap[o,f] = old(Heap(o,f))
(o,f) old(M) ¬old(Heap[o,alloc])
Modifying underlying representation
Mutable
Valid
Committed
s: Set
Hashtable
ownershiph
Fields of committed objects may change
modifies M;=
modifies Heap;ensures
(o,f •Heap[o,f] = old(Heap(o,f))
(o,f) old(M) ¬old(Heap[o,alloc]) old(Heap[o,Committed]))
So: common modifies clause• modifies this.*;
Quirk?
void M(T p)requires p.st = Committed p.x
= 12;{
int y := Math.Sqrt(…);assert p.x = 12;
}assertion failure
Default specifications
• I have showed the building blocks• A programming language would use
defaults, for example:– a method has precondition o.st=Valid
for every parameter o– public method bodies start with unpack
and end with pack– a field is owned unless declared as
shared
Further research challenges• Extend specification methodology to
more complicated programming idioms• Develop abstract interpretations that
work with object-oriented specifications• Combine abstract interpretation with
theorem proving• Use programming system among
developers
Conclusions• Because of tool support, we’re ready for
programming at the next level of rigor• Rigor can be enforced by type checking, by
run-time checking, and by static verification• Specifications give programmers a way to
record their design decisions• Methodology is underdeveloped
– “Can programming theory yet fully explain why real big programs work?”
– programming theory has not kept up with practice
http://research.microsoft.com/~leino
http://research.microsoft.com/projects/specsharp