1 / 37

Verifying invariants in object-oriented programs

Learn how to verify invariants in object-oriented programs and improve code maintainability through automatic checking. This talk discusses the A# and Boogie programming languages, their compilers, the BoogiePL weakest-precondition generator, and the use of invariants as shorthand for pre/post-conditions.

wsilver
Download Presentation

Verifying invariants in object-oriented programs

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. Verifying invariants in object-oriented programs K. Rustan M. Leino Microsoft Research, Redmond, WA, USA Joint work with Mike Barnett, Robert DeLine, Manuel Fahndrich, and Wolfram Schulte ‥ Computer Science ColloquiumETH Zurich24 Nov 2003

  2. Vision Record design decisions + Utilize automatic checking= Detect errors and improve maintainability

  3. A# and Boogie:Programmer's view A# A# compiler Other .NETcompilers C# C# compiler MSIL Boogie Warnings

  4. Boogie: under the hood MSIL translator Inferenceengine BoogiePL weakest-preconditiongenerator verification condition Theoremprover Warnings

  5. Boogie technologyand research • Programming methodology • model for writing code and specifications • Inference • abstract domains over heap structures • Verification-condition generation • formulas that are “efficient” for theorem prover

  6. Invariants: straw man Object invariants hold on public method boundaries and are shorthands for pre/post-conditions class T { // field declarations ... invariantJ ; T(...)requires Pmodifies vensures Q { … } method m(...)requires Rmodifies wensures T { … } … class T { // field declarations ... T(...)requires Pmodifies vensures Q∧ J { … } method m(...)requires R ∧ Jmodifies wensures T∧ J { … } …

  7. Invariants, example class T { privateint x, y ;invariant0 ≦ x < y ; public T() { x = 0 ; y = 1 ; } publicmethod m()modifies x, y {assert y-x ≧ 0 ; x = x + 3 ; y = 4 * y ; } … class T { privateint x, y ; public T()ensures0 ≦ x < y { x = 0 ; y = 1 ; } publicmethod m()requires0 ≦ x < ymodifies x, y ensures0 ≦ x < y {assert y-x ≧ 0 ; x = x + 3 ; y = 4 * y ; } …

  8. Invariants, problems class T { privateint x, y ;invariant 0 ≦ x < y ; public T() { x = 0 ; y = 1 ; } publicmethod m()modifies x, y {assert y-x ≧ 0 ; x = x + 3 ; y = 4 * y ; } … class T { privateint x, y ; public T()ensures 0 ≦ x < y { x = 0 ; y = 1 ; } publicmethod m()requires 0 ≦ x < y modifies x, y ensures 0 ≦ x < y {assert y-x ≧ 0 ; x = x + 3 ; y = 4 * y ; } … callers are expected to establish property about internal data structure

  9. Invariants, problems class T { privateint x, y ;invariant 0 ≦ x < y ; public T() { x = 0 ; y = 1 ; } publicmethod m()modifies x, y {assert y-x ≧ 0 ; x = x + 3 ; y = 4 * y ; } … class T { privateint x, y ; public T()ensures 0 ≦ x < y { x = 0 ; y = 1 ; } publicmethod m()requires 0 ≦ x < ymodifies x, y ensures 0 ≦ x < y {assert y-x ≧ 0 ; x = x + 3 ; y = 4 * y ; } … possible solution (?): callers don’t need to be checked for this precondition—it holds automatically!

  10. Invariants, problems class T { privateint x, y ;invariant 0 ≦ x < y ; public T() { x = 0 ; y = 1 ; } publicmethod m()modifies x, y {assert y-x ≧ 0 ; x = x + 3 ; y = 4 * y ; } … class T { privateint x, y ; public T()ensures 0 ≦ x < y { x = 0 ; y = 1 ; } publicmethod m() requires 0 ≦ x < y modifies x, y ensures 0 ≦ x < y {assert y-x ≧ 0 ; x = x + 3 ; y = 4 * y ; } … invariant does not hold here

  11. Invariants, problems class T { privateint x, y ;invariant 0 ≦ x < y ; public T() { x = 0 ; y = 1 ; } public method m()modifies x, y {assert y-x ≧ 0 ; x = x + 3 ; y = 4 * y ; } … class T { privateint x, y ; public T()ensures 0 ≦ x < y { x = 0 ; y = 1 ; } publicmethod m() requires 0 ≦ x < y modifies x, y ensures 0 ≦ x < y {assert y-x ≧ 0 ; x = x + 3 ;p(...) ; y = 4 * y ; } … invariant does not hold here, so what if p calls m?!

  12. The problem of specifying modifications class Kitchen {private Dishes d ; private bool hasGarbage ;private Stove s ;private Light l ; ... publicmethod SpiffUp()modifies hasGarbage, s.foodPieces, s.big.sufaceColor, … { d.Clean() ; hasGarbage = false ; s.Wipe() ; l.TurnOff() ; ... } class Stove {private Burner big ;private Burner small ;privateint foodPieces ;private Knob[] knobs ; ... publicmethod Wipe()modifies foodPieces, big.surfaceColor, … { big.Polish() ; small.Polish() ; foodPieces = 0 ; ... } these lists are long, and they mention private state

  13. The problem of specifying modifications class Kitchen {private Dishes d ; private bool hasGarbage ;private Stove s ;private Light l ; ... publicmethod SpiffUp()modifieshasGarbage, s.foodPieces, s.big.sufaceColor, … { d.Clean() ; hasGarbage = false ; s.Wipe() ; l.TurnOff() ; ... } class Stove {private Burner big ;private Burner small ;privateint foodPieces ;private Knob[] knobs ; ... publicmethod Wipe()modifiesfoodPieces, big.surfaceColor, … { big.Polish() ; small.Polish() ; foodPieces = 0 ; ... } possible solution (?):don’t need to declare modifications of private state—it can’t be observed anyhow

  14. The problem of specifying modifications class Kitchen {private Dishes d ; private bool hasGarbage ;private Stove s ;private Light l ; ... publicmethod SpiffUp()modifies { d.Clean() ; hasGarbage = false ; s.Wipe() ; assert ¬hasGarbage ; l.TurnOff() ; ... } class Stove {private Burner big ;private Burner small ;privateint foodPieces ;private Knob[] knobs ; ... publicmethod Wipe()modifies { big.Polish() ; small.Polish() ; foodPieces = 0 ; ... } SpiffUp treats Wipe as if Wipe modified nothing, so what if Wipe calls a method in Kitchen that sets hasGarbage to true?!

  15. Soundness of verification • Soundness = verification finds all errors • Soundness follows from: • pre- and postconditions are the same for caller and callee • Note: In addition to soundness, we want something usable

  16. Methodology • object invariant declaration • class T { int x, y ;invariant x < y ; • special variable st: {Invalid, Valid} • Idea: program invariant (∀o ・ o.st = Invalid ∨ Inv(o)) • st is changed by commands pack andunpack for any o: T, we writeInv(o)≡ o.x < o.y holds at everyprogram point!

  17. pack and unpack • pack o ≡assert o.st = Invalid ;assert Inv(o) ; o.st := Valid • unpack o ≡assert o.st = Valid ; o.st := Invalid

  18. Example receiver parameter(“this”, “self”, “current”) class T {int x, y ;invariant 0 ≦ x < y ; method init(t)requires t.st = Invalidmodifies t.st, t.x, t.yensures t.st = Valid { t.x := 0 ; t.y := 1 ;pack t } method m(t)requires t.st = Validmodifies t.x, t.y {unpack t ; t.x := t.x + 3 ; t.y := 4 * t.y ;pack t }

  19. Program invariant (∀o ・ o.st = Invalid ∨ Inv(o)) • x := new(T)≡ ... ; assume x.st = Invalid • pack o≡ ... ; assert Inv(o) ; o.st := Valid • unpack o≡ ... ; o.st := Invalid • o.f := E≡ assert o.st = Invalid ; ... • Inv(o) can mention only the fields of o

  20. Methodology, summary • invariant ... • st: {Invalid, Valid} • pack, unpack • modifications of o.f require o.st=Invalid • Inv(o) can mention only the fields of o • (∀o ・ o.st = Invalid ∨ Inv(o))

  21. Methodology, extended • component declarations • class Kitchen {component Stove s ; • st: {Invalid, Valid, Committed} • Idea: program invariant(∀o ・ o.st=Invalid ∨ (Inv(o) ∧ (∀p∈Comp(o) ・ p.st=Committed))) • pack o and unpack o change st for o and o's components for any k: Kitchen, we havek.s ∈ Comp(k)

  22. pack and unpack, extended • pack o ≡assert o.st = Invalid ∧ Inv(o) ;assert (∀p ∈ Comp(o) ・ p.st=Valid) ; o.st := Valid ;foreachp ∈ Comp(o)do p.st :=Committed ; • unpack o ≡assert o.st = Valid ;foreachp ∈ Comp(o)do p.st=Valid ; o.st := Invalid ;

  23. Example class Stove {method Wipe(s)requires s.st=Valid … class Kitchen { method SpiffUp(k)requires k.st=Valid … {unpack k ; k.d.Clean() ; k.s.Wipe() ;pack k } Committed Committed Dishes Committed Committed Stove s d Committed k Kitchen Valid

  24. Example class Stove {method Wipe(s)requires s.st=Valid … class Kitchen { method SpiffUp(k)requires k.st=Valid … {unpack k ; k.d.Clean() ; k.s.Wipe() ;pack k } Committed Committed Dishes Committed Committed Valid Stove s d Committed Valid k Kitchen Valid Invalid

  25. Program invariant (∀o ・ o.st=Invalid ∨ (Inv(o) ∧ (∀p∈Comp(o) ・ p.st=Committed))) • x := new(T)≡ ... ; assume x.st=Invalid • pack o, unpack o • o.f := E≡ assert o.st=Invalid ; ... • Inv(o) can mention only the fields of o andof o.p for any component field p

  26. Extended methodology, summary • invariant ... • component ... • st: {Invalid, Valid, Committed} • pack, unpack • modifications of o.f require o.st=Invalid • Inv(o) can mention only the fields of o and of o.p for any component field p • (∀o ・ o.st=Invalid ∨ (Inv(o) ∧ (∀p∈Comp(o) ・ p.st=Committed)))

  27. Verification system • We let st be used in method specifications (requires, modifies, ensures) • We must address the Problem of Specifying Modifications

  28. A heap model • Heap is a two-dimensional “array” class T { f: U; g: V; ... } • x := o.f = x := Heap[o, f] • o.f := E = Heap[o, f] := E

  29. Meaning of modifies • modifies w =modifies Heapensures (∀o,f ・ Heap[o,f] = Heap0[o,f] ∨ (o,f) ∈ w0 ) viewed as set of object/field-name pairs

  30. Meaning of modifies • modifies w =modifies Heapensures (∀o,f ・ Heap[o,f] = Heap0[o,f] ∨ (o,f) ∈ w0 ∨ ¬Heap0[o,alloc] )

  31. Meaning of modifies • modifies w =modifies Heapensures (∀o,f ・ Heap[o,f] = Heap0[o,f] ∨ (o,f) ∈ w0 ∨ ¬Heap0[o,alloc] ∨ Heap0[o,st]=Committed )

  32. Example class Stove {method Wipe(s)requires s.st=Validmodifies s.foodPieces class Kitchen { method SpiffUp(k)requires k.st=Validmodifies k.hasGarbage {unpack k ; k.d.Clean() ; k.hasGarbage := false ; k.s.Wipe() ;assert¬k.hasGarbage ;pack k }

  33. Another example method m(p)requires p.st=Committed{var y, z in y := p.x ; z := sqrt(49) ;assert y = p.xend}

  34. Soundness • Pre- and postconditions are the same for callers and callees, so verification system is sound!

  35. Related work • rep types in CLU • dynamically checked invariants in Eiffel • valid idiom in ESC/Modula-3 • universe types and invariants in Muller's thesis • invariant declarations in ESC/Java and JML • (implicit) pack/unpack operations in Vault and Fugue • capability calculus • ownership types • locking and monitor disciplines in concurrent programming ‥

  36. Conclusions • Invariants different from pre/post-conditions • Resulting program invariants hold at every program point • Uses pack/unpack commands, but good defaults can be constructed for these • No linear type system • Components are not unique references—objects (pointers) can freely be copied • Fields can freely be read • No additional features of abstraction needed to support the specification of modifications • Sound ‥

  37. Further research challenges • experience, understanding of limits • extensions to support more good programs(joint work with Peter Muller) ‥

More Related