A Considerate Specification of the Composite Pattern Alexander J. Summers Sophia Drossopoulou Imperial College London Imperial College London
Overview Specification of the Composite pattern SAVCBS challenge problem last year Invariant protocol based on Middelkoop et. al. 2006 Idea: “Considerate Reasoning” (IWACO 2009) objects are concerned with each others’ invariants Implementation and verification in Boogie2 Encoding the invariant protocol Simplifying the resulting proof obligations Practical handling of quantified formulas
The Composite pattern A tree whose nodes preserve properties related to all their descendant leaves. Subtrees may be added directly without first visiting their parents. We ignore subclassing issues for this talk, and treat a single class Composite
The Composite pattern suggested as a specification/verification challenge by Mueller, Leavens and Poetzsch-Heffter Various solutions proposed at SACVBS’08 We describe its specification and verification using invariants, adapting approach suggested by Middelkoop et. al. What we’re going to talk about the effect of different connectives on term calculi Write this at the end, when all other slides are done.#
The Composite class class Composite int total; Composite parent; Composite[] components; int count; void addComponent(Composite c); … }
The Composite class 7 class Composite int total; Composite parent; Composite[] components; int count; void addComponent(Composite c); … } 4 3 2 2 2 1
The Composite class 7 class Composite int total; Composite parent; Composite[] components; int count; void addComponent(Composite c); … } 4 3 2 2 2 1 The field parent points to the parent node. The fields components and count maintain pointers to all children – i.e., the inverse of parent.
The Composite - invariant 2 2 2 1
The Composite - invariant Each node has a value which is the sum of the values of all its descendant leaves. 2 2 2 1
The Composite - invariant Each node has a value which is the sum of the values of all its descendant leaves. 7 2 2 2 1
The Composite - invariant Each node has a value which is the sum of the values of all its descendant leaves. 7 4 2 2 2 1
The Composite - invariant Each node has a value which is the sum of the values of all its descendant leaves. 7 4 3 2 2 2 1
The Composite - invariant Each node has a value which is the sum of the values of all its descendant leaves. P(n) <=> n.total = (lf.total), where lf a leaf under n 7 4 3 2 2 2 1
The Composite - invariant Each node has a value which is the sum of the values of all its descendant leaves. P(n) <=> n.total = (lf.total), where lf a leaf under n 7 4 3 2 2 2 1
The Composite - invariant Each node has a value which is the sum of the values of all its descendant leaves. P(n) <=> n.total = (lf.total), where lf a leaf under n 7 4 3 2 2 2 1 P(n) is a non-local predicate
The Composite - invariant - local Each node has a value which is the sum of the values of all its direct descendants. 2 2 2 1
The Composite - invariant - local Each node has a value which is the sum of the values of all its direct descendants. Q(n) <=> n.total = (n’.total), where n’.parent=this 2 2 2 1
The Composite - invariant - local Each node has a value which is the sum of the values of all its direct descendants. Q(n) <=> n.total = (n’.total), where n’.parent=this 4 2 2 2 1
The Composite - invariant - local Each node has a value which is the sum of the values of all its direct descendants. Q(n) <=> n.total = (n’.total), where n’.parent=this 4 3 2 2 2 1
The Composite - invariant - local Each node has a value which is the sum of the values of all its direct descendants. Q(n) <=> n.total = (n’.total), where n’.parent=this 7 4 3 2 2 2 1
Local invariants achieve as much P(n) n.total = (lf.total), where lf a leaf under n P(n) is non-local Q(n) n.total = (n’.total), where n’.parent=this Q(n) is local P(n) is stronger than Q(n) n. P(n) n. Q(n) We will be using Q(n) as the invariant for n InvTwo: total == 1 + Sum(i=0..count)::components[i].total
The Composite - code void addComponent(Composite c) { components[count]=c; count ++; c.parent = this; addToTotal( c.total ); }
The Composite - code void addComponent(Composite c) { components[count]=c; count ++; c.parent = this; addToTotal( c.total ); } void addToTotal(int t){ total=total+t; if (parent!=null){ parent.addToTotal(t);
The Composite - code this c void addComponent(Composite c) { components[count]=c; count ++; c.parent = this; addToTotal( c.total ); } void addToTotal(int t){ total=total+t; if (parent!=null){ parent.addToTotal(t); this c
The Composite - code this c void addComponent(Composite c) { components[count]=c; count ++; c.parent = this; addToTotal( c.total ); } void addToTotal(int t){ total=total+t; if (parent!=null){ parent.addToTotal(t); this c
The Composite - code this c void addComponent(Composite c) { components[count]=c; count ++; c.parent = this; addToTotal( c.total); } void addToTotal(int t){ total=total+t; if (parent!=null){ parent.addToTotal(t); this c
The Composite - code this void addComponent(Composite c) { components[count]=c; count ++; c.parent = this; addToTotal( c.total); } void addToTotal(int t){ total=total+t; if (parent!=null){ parent.addToTotal(t); this
The Composite - code this void addComponent(Composite c) { components[count]=c; count ++; c.parent = this; addToTotal( c.total); } void addToTotal(int t){ total=total+t; if (parent!=null){ parent.addToTotal(t); this
The Composite - code this void addComponent(Composite c) { components[count]=c; count ++; c.parent = this; addToTotal( c.total); } void addToTotal(int t){ total=total+t; if (parent!=null){ parent.addToTotal(t); this
The Composite - add a subtree The Composite - code The Composite - add a subtree void addComponent(Composite c) { components[count]=c; count ++; c.parent = this; addToTotal( c.total); } void addToTotal(int t){ total=total+t; if (parent!=null){ parent.addToTotal(t); this
The Composite - code this void addComponent(Composite c) { components[count]=c; count ++; c.parent = this; addToTotal(c.total); } void addToTotal(int t){ total=total+t; if (parent!=null){ parent.addToTotal(t); this
The Composite - code this void addComponent(Composite c) { components[count]=c; count ++; c.parent = this; addToTotal(c.total); } void addToTotal(int t){ total=total+t; if (parent!=null){ parent.addToTotal(t); this
The Composite - code this void addComponent(Composite c) { components[count]=c; count ++; c.parent = this; addToTotal(c.total); } void addToTotal(int t){ total=total+t; if (parent!=null){ parent.addToTotal(t); this
The Composite - code this void addComponent(Composite c) { components[count]=c; count ++; c.parent = this; addToTotal(c.total); } void addToTotal(int t){ total=total+t; if (parent!=null){ parent.addToTotal(t); this
The Composite - code this void addComponent(Composite c) { components[count]=c; count ++; c.parent = this; addToTotal(c.total); } void addToTotal(int t){ total=total+t; if (parent!=null){ parent.addToTotal(t); this
The Composite class - invariant revisited 7 class Composite int total; Composite parent; Composite[] components; int count; } 4 3 2 2 2 1
The Composite class - invariant revisited 7 class Composite int total; Composite parent; Composite[] components; int count; } 4 3 2 2 2 1 InvOne: total > 0 && count ≥ 0
The Composite class - invariant revisited 7 class Composite int total; Composite parent; Composite[] components; int count; } 4 3 2 2 2 1 InvOne: total > 0 && count ≥ 0 InvTwo: total == 1 + Sum(i=0..count) :: components[i].total
The Composite class - invariant revisited 7 class Composite int total; Composite parent; Composite[] components; int count; } 4 3 2 2 2 1 InvThree: i::components[i].parent == this
The Composite class - invariant revisited 7 class Composite int total; Composite parent; Composite[] components; int count; } 4 3 2 2 2 1 InvThree: i::components[i].parent == this InvFour: this.parent != null i::this.parent.components[i] == this
The Composite class - invariant revisited 7 class Composite int total; Composite parent; Composite[] components; int count; } 4 3 2 2 2 1 InvThree: i::components[i].parent == this InvFour: this.parent != null i::this.parent.components[i] == this Essentially, parent and components are inverses
Visible States Semantics One basic philosophy for multi-object invariants Idea: invariants can be temporarily broken Must be fixed by the end of each method body Must also be fixed before making further calls In simplest form, all invariants hold at these points Many invariant protocols are based on this idea We use a variant based on Middelkoop et. al. First, basic visible states implemented in Boogie2
Visible State Semantics in Boogie2 public void addComponent(Composite c) { components[count] = c; count++; c.parent = this; this.addToTotal(c.total); }
Visible State Semantics in Boogie2 public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; this.addToTotal(c.total); }
Visible State Semantics in Boogie2 public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; this.addToTotal(c.total); }
Visible State Semantics in Boogie2 public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; this.addToTotal(c.total); } assume o :: InvOne(o)
Visible State Semantics in Boogie2 public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; this.addToTotal(c.total); } assume o :: InvOne(o) assume o :: InvTwo(o) assume o :: InvThree(o) assume o :: InvFour(o)
Visible State Semantics in Boogie2 public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; this.addToTotal(c.total); }
Visible State Semantics in Boogie2 public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; this.addToTotal(c.total); assert all invariants.. }
Visible State Semantics in Boogie2 public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; this.addToTotal(c.total); assert all invariants.. } assert o :: InvOne(o) assert o :: InvTwo(o) assert o :: InvThree(o) assert o :: InvFour(o)
Visible State Semantics in Boogie2 public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; this.addToTotal(c.total); assert all invariants.. }
Visible State Semantics in Boogie2 public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all invariants.. this.addToTotal(c.total); }
Visible State Semantics in Boogie2 public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all invariants.. this.addToTotal(c.total); }
Visible State Semantics in Boogie2 public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all invariants.. this.addToTotal(c.total); }
Visible State Semantics in Boogie2 public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all invariants.. this.addToTotal(c.total); } But, addToTotal is meant to fix an invariant which is currently broken!
Handling “broken” invariants We need to allow exceptions to visible states rules Want to allow an invariant to be broken for a call Idea: add a specification construct broken Method signatures can declare “broken” invariants: InvTwo(this) need not hold before calling However, must be established by the method end Related to the INC construct of Middelkoop et. al. // broken: InvTwo(this) private void addToTotal() { ...
Handling “broken” invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all invariants.. this.addToTotal(c.total); }
Handling “broken” invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all invariants.. this.addToTotal(c.total); }
Handling “broken” invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all invariants.. this.addToTotal(c.total); } private void addToTotal() { ...
Handling “broken” invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all invariants.. this.addToTotal(c.total); } // broken: InvTwo(this) private void addToTotal() { ...
Handling “broken” invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all invariants.. this.addToTotal(c.total); } // broken: InvTwo(this) private void addToTotal() { ...
Handling “broken” invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all invariants.. this.addToTotal(c.total); } // broken: InvTwo(this) private void addToTotal() { ... assert o :: InvOne(o) assert o :: InvTwo(o) assert o :: InvThree(o) assert o :: InvFour(o)
Handling “broken” invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all invariants.. this.addToTotal(c.total); } // broken: InvTwo(this) private void addToTotal() { ... assert o :: InvOne(o) assert o :: InvTwo(o) assert o :: InvThree(o) assert o :: InvFour(o)
Handling “broken” invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all invariants.. this.addToTotal(c.total); } // broken: InvTwo(this) private void addToTotal() { ... assert o :: InvOne(o) assert o :: o!=this InvTwo(o) assert o :: InvThree(o) assert o :: InvFour(o)
Handling “broken” invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); assert all invariants.. } assert o :: InvOne(o) assert o :: o!=this InvTwo(o) assert o :: InvThree(o) assert o :: InvFour(o)
Handling “broken” invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); assert all invariants.. }
Problem: Quantifiers in Assertions Asserting invariants for all objects is excessive Also, leaves a lot of work to the prover
Problem: Quantifiers in Assertions Asserting invariants for all objects is excessive Also, leaves a lot of work to the prover void m() { // code.. }
Problem: Quantifiers in Assertions Asserting invariants for all objects is excessive Also, leaves a lot of work to the prover void m() { // code.. } assume o :: Inv(o)
Problem: Quantifiers in Assertions Asserting invariants for all objects is excessive Also, leaves a lot of work to the prover void m() { // code.. } assume o :: Inv(o) assert o :: Inv(o)
Problem: Quantifiers in Assertions Asserting invariants for all objects is excessive Also, leaves a lot of work to the prover void m() { // code.. } assume o :: Inv(o) assert o :: Inv(o)
Problem: Quantifiers in Assertions Asserting invariants for all objects is excessive Also, leaves a lot of work to the prover void m() { // code.. } assume o :: Inv(o) assert o :: Inv(o)
Problem: Quantifiers in Assertions Asserting invariants for all objects is excessive Also, leaves a lot of work to the prover void m() { // code.. } assume o :: Inv(o) assert o :: Inv(o)
Problem: Quantifiers in Assertions Asserting invariants for all objects is excessive Also, leaves a lot of work to the prover Which assertions trivial, and which require work? void m() { // code.. } assume o :: Inv(o) assert o :: Inv(o)
Coop-sets to track invariants Idea: track which invariants depend on which fields Middelkoop et. al. – each field gets a “coop set” Declares which invariants may be broken by modifying this field Coop sets consist of pairs (I, P), where... I names an invariant which depends on the field P is a predicate describing when this invariant might be broken by modifying the field, in which: this denotes the object whose field is modified o denotes the object whose invariant may be broken
Coop-sets to track invariants
Coop-sets to track invariants InvOne: total > 0 && count ≥ 0
Coop-sets to track invariants InvOne: total > 0 && count ≥ 0 InvTwo: total == 1 + Sum(i=0..count) :: components[i].total ...
Coop-sets to track invariants InvOne: total > 0 && count ≥ 0 InvTwo: total == 1 + Sum(i=0..count) :: components[i].total ... private int total; // coop:
Coop-sets to track invariants InvOne: total > 0 && count ≥ 0 InvTwo: total == 1 + Sum(i=0..count) :: components[i].total ... private int total; // coop:
Coop-sets to track invariants InvOne: total > 0 && count ≥ 0 InvTwo: total == 1 + Sum(i=0..count) :: components[i].total ... private int total; // coop: (InvOne,o==this)
Coop-sets to track invariants InvOne: total > 0 && count ≥ 0 InvTwo: total == 1 + Sum(i=0..count) :: components[i].total ... private int total; // coop: (InvOne,o==this)
Coop-sets to track invariants InvOne: total > 0 && count ≥ 0 InvTwo: total == 1 + Sum(i=0..count) :: components[i].total ... private int total; // coop: (InvOne,o==this)
Coop-sets to track invariants InvOne: total > 0 && count ≥ 0 InvTwo: total == 1 + Sum(i=0..count) :: components[i].total ... private int total; // coop: (InvOne,o==this), (InvTwo,o==this)
Coop-sets to track invariants InvOne: total > 0 && count ≥ 0 InvTwo: total == 1 + Sum(i=0..count) :: components[i].total ... private int total; // coop: (InvOne,o==this), (InvTwo,o==this)
Coop-sets to track invariants InvOne: total > 0 && count ≥ 0 InvTwo: total == 1 + Sum(i=0..count) :: components[i].total ... private int total; // coop: (InvOne,o==this), (InvTwo,o==this)
Coop-sets to track invariants InvOne: total > 0 && count ≥ 0 InvTwo: total == 1 + Sum(i=0..count) :: components[i].total ... private int total; // coop: (InvOne,o==this), (InvTwo,o==this) // (InvTwo, i :: o.components[i] == this)
Coop-sets to track invariants InvOne: total > 0 && count ≥ 0 InvTwo: total == 1 + Sum(i=0..count) :: components[i].total ... private int total; // coop: (InvOne,o==this), (InvTwo,o==this) // (InvTwo, i :: o.components[i] == this)
Coop-sets to track invariants InvOne: total > 0 && count ≥ 0 InvTwo: total == 1 + Sum(i=0..count) :: components[i].total ... private int total; // coop: (InvOne,o==this), (InvTwo,o==this) // (InvTwo, i :: o.components[i] == this) Use the coop-sets to calculate the vulnerable invariants
Coop-sets to track invariants InvOne: total > 0 && count ≥ 0 InvTwo: total == 1 + Sum(i=0..count) :: components[i].total ... private int total; // coop: (InvOne,o==this), (InvTwo,o==this) // (InvTwo, i :: o.components[i] == this) Use the coop-sets to calculate the vulnerable invariants Note: the objects o are not obviously reachable from this
Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); assert all invariants.. }
Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); assert all invariants.. }
Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total);
Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total);
Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); Vulnerable Invariants
Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); Vulnerable Invariants
Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); private Composite[] components; Vulnerable Invariants
Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); private Composite[] components; // coop: (InvThree,o==this) // (InvFour,o.parent==this) Vulnerable Invariants
Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); private Composite[] components; // coop: (InvThree,o==this) // (InvFour,o.parent==this) Vulnerable Invariants InvThree(this)
Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); private Composite[] components; // coop: (InvThree,o==this) // (InvFour,o.parent==this) Vulnerable Invariants InvThree(this), o :: o.parent==this InvFour(o)
Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); private Composite[] components; // coop: (InvThree,o==this) // (InvFour,o.parent==this) Vulnerable Invariants InvThree(this), o :: o.parent==this InvFour(o) Note: coop wrong
Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); Vulnerable Invariants InvThree(this), o :: o.parent==this InvFour(o)
Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); Vulnerable Invariants InvThree(this), o :: o.parent==this InvFour(o)
Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); private int count; // coop: (InvOne,o==this) // (InvTwo,o==this) // (InvThree,o==this) // (InvFour,o.parent==this) Vulnerable Invariants InvThree(this), o :: o.parent==this InvFour(o)
Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); private int count; // coop: (InvOne,o==this) // (InvTwo,o==this) // (InvThree,o==this) // (InvFour,o.parent==this) Vulnerable Invariants InvThree(this), o :: o.parent==this InvFour(o), InvOne(this)
Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); private int count; // coop: (InvOne,o==this) // (InvTwo,o==this) // (InvThree,o==this) // (InvFour,o.parent==this) Vulnerable Invariants InvThree(this), o :: o.parent==this InvFour(o), InvOne(this), InvTwo(this)
Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); private int count; // coop: (InvOne,o==this) // (InvTwo,o==this) // (InvThree,o==this) // (InvFour,o.parent==this) Vulnerable Invariants InvThree(this), o :: o.parent==this InvFour(o), InvOne(this), InvTwo(this), InvThree(this)
Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); private int count; // coop: (InvOne,o==this) // (InvTwo,o==this) // (InvThree,o==this) // (InvFour,o.parent==this) Vulnerable Invariants InvThree(this), o :: o.parent==this InvFour(o), InvOne(this), InvTwo(this), InvThree(this), o :: o.parent==this InvFour(o)
Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); Vulnerable Invariants InvThree(this), o :: o.parent==this InvFour(o), InvOne(this), InvTwo(this), InvThree(this), o :: o.parent==this InvFour(o)
Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); Vulnerable Invariants InvThree(this), o :: o.parent==this InvFour(o), InvOne(this), InvTwo(this), InvThree(this), o :: o.parent==this InvFour(o)
Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); Vulnerable Invariants InvThree(this), o :: o.parent==this InvFour(o), InvOne(this), InvTwo(this), InvThree(this)
Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); Vulnerable Invariants InvThree(this), o :: o.parent==this InvFour(o), InvOne(this), InvTwo(this), InvThree(this)
Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); Vulnerable Invariants InvThree(this), o :: o.parent==this InvFour(o), InvOne(this), InvTwo(this)
Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); Vulnerable Invariants InvThree(this), o :: o.parent==this InvFour(o), InvOne(this), InvTwo(this)
Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); private Composite parent; // coop: (InvFour,o==this) // (InvThree,(i :: this==o.components[i])) Vulnerable Invariants InvThree(this), o :: o.parent==this InvFour(o), InvOne(this), InvTwo(this)
Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); private Composite parent; // coop: (InvFour,o==this) // (InvThree,(i :: this==o.components[i])) Vulnerable Invariants InvThree(this), o :: o.parent==this InvFour(o), InvOne(this), InvTwo(this), InvFour(c)
Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); private Composite parent; // coop: (InvFour,o==this) // (InvThree,(i :: this==o.components[i])) Vulnerable Invariants InvThree(this), o :: o.parent==this InvFour(o), InvOne(this), InvTwo(this), InvFour(c), o :: (i :: c==o.components[i]) InvThree(o)
Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); Vulnerable Invariants InvThree(this), o :: o.parent==this InvFour(o), InvOne(this), InvTwo(this), InvFour(c), o :: (i :: c==o.components[i]) InvThree(o)
Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); Vulnerable Invariants InvThree(this), o :: o.parent==this InvFour(o), InvOne(this), InvTwo(this), InvFour(c), o :: (i :: c==o.components[i]) InvThree(o)
Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); Vulnerable Invariants InvThree(this), o :: o.parent==this InvFour(o), InvOne(this), InvTwo(this), InvFour(c), o :: (i :: c==o.components[i]) InvThree(o)
Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); Vulnerable Invariants InvThree(this), o :: o.parent==this InvFour(o), InvOne(this), InvFour(c), o :: (i :: c==o.components[i]) InvThree(o)
Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); Vulnerable Invariants aInvThree(this), ao :: o.parent==this InvFour(o), aInvOne(this), aInvFour(c), ao :: (i :: c==o.components[i]) InvThree(o)
Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); Vulnerable Invariants asInvThree(this), aso :: o.parent==this InvFour(o), asInvOne(this), asInvFour(c), aso :: (i :: c==o.components[i]) InvThree(o)
Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); Vulnerable Invariants assInvThree(this), asso :: o.parent==this InvFour(o), assInvOne(this), assInvFour(c), asso :: (i :: c==o.components[i]) InvThree(o)
Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); Vulnerable Invariants asseInvThree(this), asseo :: o.parent==this InvFour(o), asseInvOne(this), asseInvFour(c), asseo :: (i :: c==o.components[i]) InvThree(o)
Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); Vulnerable Invariants asserInvThree(this), assero :: o.parent==this InvFour(o), asserInvOne(this), asserInvFour(c), assero :: (i :: c==o.components[i]) InvThree(o)
Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); Vulnerable Invariants assertInvThree(this), asserto :: o.parent==this InvFour(o), assertInvOne(this), assertInvFour(c), asserto :: (i :: c==o.components[i]) InvThree(o)
Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); Vulnerable Invariants assert InvThree(this), assert o :: o.parent==this InvFour(o), assert InvOne(this), assert InvFour(c), assert o :: (i :: c==o.components[i]) InvThree(o)
Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert all except “broken” invariants.. this.addToTotal(c.total); Vulnerable Invariants assert InvThree(this), assert o :: o.parent==this InvFour(o), assert InvOne(this), assert InvFour(c), assert o :: (i :: c==o.components[i]) InvThree(o)
Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert vulnerable except “broken” invariants.. this.addToTotal(c.total); Vulnerable Invariants assert InvThree(this), assert o :: o.parent==this InvFour(o), assert InvOne(this), assert InvFour(c), assert o :: (i :: c==o.components[i]) InvThree(o)
Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert vulnerable except “broken” invariants.. this.addToTotal(c.total); assert o :: InvOne(o) assert o :: o!=this InvTwo(o) assert o :: InvThree(o) assert o :: InvFour(o) Vulnerable Invariants assert InvThree(this), assert o :: o.parent==this InvFour(o), assert InvOne(this), assert InvFour(c), assert o :: (i :: c==o.components[i]) InvThree(o)
Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert vulnerable except “broken” invariants.. this.addToTotal(c.total); assert o :: InvOne(o) assert o :: o!=this InvTwo(o) assert o :: InvThree(o) assert o :: InvFour(o) Vulnerable Invariants assert InvThree(this), assert o :: o.parent==this InvFour(o), assert InvOne(this), assert InvFour(c), assert o :: (i :: c==o.components[i]) InvThree(o)
Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert vulnerable except “broken” invariants.. this.addToTotal(c.total); assert o :: InvOne(o) assert o :: o!=this InvTwo(o) assert o :: InvThree(o) assert o :: InvFour(o) Vulnerable Invariants assert InvThree(this), assert o :: o.parent==this InvFour(o), assert InvOne(this), assert InvFour(c), assert o :: (i :: c==o.components[i]) InvThree(o)
Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert vulnerable except “broken” invariants.. this.addToTotal(c.total); assert o :: InvOne(o) assert o :: o!=this InvTwo(o) assert o :: InvThree(o) assert o :: InvFour(o) Vulnerable Invariants assert InvThree(this), assert o :: o.parent==this InvFour(o), assert InvOne(this), assert InvFour(c), assert o :: (i :: c==o.components[i]) InvThree(o)
Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert vulnerable except “broken” invariants.. this.addToTotal(c.total); assert o :: InvOne(o) assert o :: o!=this InvTwo(o) assert o :: InvThree(o) assert o :: InvFour(o) FEWER INVARIANTS ASSERTED Vulnerable Invariants assert InvThree(this), assert o :: o.parent==this InvFour(o), assert InvOne(this), assert InvFour(c), assert o :: (i :: c==o.components[i]) InvThree(o)
Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert vulnerable except “broken” invariants.. this.addToTotal(c.total); assert o :: InvOne(o) assert o :: o!=this InvTwo(o) assert o :: InvThree(o) assert o :: InvFour(o) FEWER INVARIANTS ASSERTED Vulnerable Invariants assert InvThree(this), assert o :: o.parent==this InvFour(o), assert InvOne(this), assert InvFour(c), assert o :: (i :: c==o.components[i]) InvThree(o)
Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert vulnerable except “broken” invariants.. this.addToTotal(c.total); assert o :: InvOne(o) assert o :: o!=this InvTwo(o) assert o :: InvThree(o) assert o :: InvFour(o) Vulnerable Invariants assert InvThree(this), assert o :: o.parent==this InvFour(o), assert InvOne(this), assert InvFour(c), assert o :: (i :: c==o.components[i]) InvThree(o)
Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert vulnerable except “broken” invariants.. this.addToTotal(c.total); assert o :: InvOne(o) assert o :: o!=this InvTwo(o) assert o :: InvThree(o) assert o :: InvFour(o) Vulnerable Invariants assert InvThree(this), assert o :: o.parent==this InvFour(o), assert InvOne(this), assert InvFour(c), assert o :: (i :: c==o.components[i]) InvThree(o)
Calculating vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert vulnerable except “broken” invariants.. this.addToTotal(c.total); assert o :: InvOne(o) assert o :: o!=this InvTwo(o) assert o :: InvThree(o) assert o :: InvFour(o) Vulnerable Invariants assert InvThree(this), assert o :: o.parent==this InvFour(o), assert InvOne(this), assert InvFour(c), assert o :: (i :: c==o.components[i]) InvThree(o)
Refining vulnerable invariants InvThree and InvFour express that components and parent are “inverses” If we use this information, we can refine assertions For example: assert o :: (i :: c==o.components[i]) InvThree(o) “those objects which have c in their components” The only possible such object is c.parent : assert (c.parent != null) InvThree(c.parent) This assertion concerns a (single) object to which we have direct field access This reduces the burden of work on the prover
Refining vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert vulnerable except “broken” invariants.. this.addToTotal(c.total); Vulnerable Invariants assert InvThree(this), assert o :: o.parent==this InvFour(o), assert InvOne(this), assert InvFour(c), assert o :: (i :: c==o.components[i]) InvThree(o)
Refining vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert vulnerable except “broken” invariants.. this.addToTotal(c.total); Vulnerable Invariants assert InvThree(this), assert o :: o.parent==this InvFour(o), assert InvOne(this), assert InvFour(c), assert o :: (i :: c==o.components[i]) InvThree(o)
Refining vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert vulnerable except “broken” invariants.. this.addToTotal(c.total); o.parent==this othis.components Vulnerable Invariants assert InvThree(this), assert o :: o.parent==this InvFour(o), assert InvOne(this), assert InvFour(c), assert o :: (i :: c==o.components[i]) InvThree(o)
Refining vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert vulnerable except “broken” invariants.. this.addToTotal(c.total); o.parent==this othis.components Vulnerable Invariants assert InvThree(this), assert (i :: o==this.components[i]) InvFour(o), assert InvOne(this), assert InvFour(c), assert o :: (i :: c==o.components[i]) InvThree(o)
Refining vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert vulnerable except “broken” invariants.. this.addToTotal(c.total); Vulnerable Invariants assert InvThree(this), assert (i :: o==this.components[i]) InvFour(o), assert InvOne(this), assert InvFour(c), assert o :: (i :: c==o.components[i]) InvThree(o)
Refining vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert vulnerable except “broken” invariants.. this.addToTotal(c.total); Vulnerable Invariants assert InvThree(this), assert (i :: o==this.components[i]) InvFour(o), assert InvOne(this), assert InvFour(c), assert o :: (i :: c==o.components[i]) InvThree(o)
Refining vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert vulnerable except “broken” invariants.. this.addToTotal(c.total); co.components c.parent == o Vulnerable Invariants assert InvThree(this), assert (i :: o==this.components[i]) InvFour(o), assert InvOne(this), assert InvFour(c), assert o :: (i :: c==o.components[i]) InvThree(o)
Refining vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert vulnerable except “broken” invariants.. this.addToTotal(c.total); co.components c.parent == o Vulnerable Invariants assert InvThree(this), assert (i :: o==this.components[i]) InvFour(o), assert InvOne(this), assert InvFour(c), assert (c.parent != null) InvThree(c.parent)
Refining vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert vulnerable except “broken” invariants.. this.addToTotal(c.total); Vulnerable Invariants assert InvThree(this), assert (i :: o==this.components[i]) InvFour(o), assert InvOne(this), assert InvFour(c), assert (c.parent != null) InvThree(c.parent)
Refining vulnerable invariants public void addComponent(Composite c) { assume all invariants.. components[count] = c; count++; c.parent = this; assert vulnerable except “broken” invariants.. this.addToTotal(c.total); Vulnerable Invariants assert InvThree(this), assert (i :: o==this.components[i]) InvFour(o), assert InvOne(this), assert InvFour(c), assert (c.parent != null) InvThree(c.parent)
Quantifiers in assumptions Assuming all invariants is logically very powerful However, in practice this can give too much information to the theorem prover assume o :: InvOne(o) .... InvOne(this)
Quantifiers in assumptions Assuming all invariants is logically very powerful However, in practice this can give too much information to the theorem prover assume o :: InvOne(o) .... InvOne(this), InvOne(this.parent)
Quantifiers in assumptions Assuming all invariants is logically very powerful However, in practice this can give too much information to the theorem prover assume o :: InvOne(o) .... InvOne(this), InvOne(this.parent), InvOne(this.parent.parent)... We can use “triggers” on quantified formulas to control when the prover instantiates them Rule: the prover has to “know about” a term which matches the trigger, to be allowed to instantiate
Quantifiers in assumptions Without choosing appropriate triggers, we get looping and unpredictable results Invariant definitions are guarded by triggers: The invariant name, e.g. InvOne(o) Some additional triggers: hint when it might be useful Invariants assumed/asserted in code are also guarded: Only instantiate if the invariant is determined to be relevant at some point in the method body. This can be by explicitly mentioning it, or because its definition is triggered as above. Resulting specification is well-behaved!
Results Our specification in Boogie encodes our intended invariant-based argument naturally and precisely The specification verifies (in about 5 seconds) No additional assertions are needed in the code: only those specified by the invariant protocol The calculation of vulnerable invariants from coop-sets could be easily automated The calculation of coop-sets themselves is by hand, but we believe could be partially automated The essential simplification is gained by knowing “inverse” relationships between fields
Conclusions and Future Work Invariant-based approach handles this example Resulting specification is simple, compared with “direct” approaches, and could be automated Simplifications of vulnerable invariants require some extra work The approach extends to other more-complex examples (with cycles etc.). The treatment of invariants we have used does not extend easily to client-provider relationships A combination with other approaches (e.g., ownership) would be more flexible
Finally…
Any questions? Thank you for listening! What we’re going to talk about the effect of different connectives on term calculi Write this at the end, when all other slides are done.#