Presentation is loading. Please wait.

Presentation is loading. Please wait.

Introduction to Spec# Programming System Yossi Peery Advanced SW Tools Seminar TAU Nov 2006.

Similar presentations


Presentation on theme: "Introduction to Spec# Programming System Yossi Peery Advanced SW Tools Seminar TAU Nov 2006."— Presentation transcript:

1 Introduction to Spec# Programming System Yossi Peery Advanced SW Tools Seminar TAU Nov 2006

2 Spec# Spec# = C# + contracts Spec# = C# + contracts 3 levels of checking 3 levels of checking static type checking static type checking runtime checking runtime checking program verification program verification Boogie verifier Boogie verifier Simplify theorem prover Simplify theorem prover Tool support integrated with MS Visual Studio Tool support integrated with MS Visual Studio

3 Non-null types Each reference type T includes the value null Each reference type T includes the value null Spec#’s type T! contains only references to objects of type T (not null ). Spec#’s type T! contains only references to objects of type T (not null ).

4 Types versus Assertions Without non-null types: Without non-null types: Person(string name) requires name != null; requires name != null; With non-null types: With non-null types: Person(string/*^!^*/ name) [Q] What is the difference?

5 Non-null types are flow-sensitive The non-null type of an expression is flow-sensitive. The non-null type of an expression is flow-sensitive. void Foo(T o) { if (o != null) if (o != null) T! p = o; // OK! T! p = o; // OK!} That is, it does not follow uniquely from the declared types of the variables and members mentioned in the expression.

6 Non-null Fields and Object Creation abstract class C { public C() { this.M(); } public C() { this.M(); } public abstract int M(); public abstract int M();} class D : C { T! f; T! f; D(T! x) : base() { D(T! x) : base() { f = x; f = x; } public override int M{ return f.g; } public override int M{ return f.g; }} class D : C { T! f; T! f; D(T! x) { D(T! x) { f = x; f = x; base() } public override int M{ return f.g; } public override int M{ return f.g; }}

7 Non-nullness of Fields Common coding pattern: if (o.f != null) o.f.Foo(); o.f.Foo(); [Q] How can this go wrong?

8 Non-nullness of Properties Common coding pattern: if (o.P != null) o.P.Foo(); o.P.Foo(); [Q] How can this go wrong?

9 Fields and Properties For the non-null dataflow analysis, it is assumed that non-nullness of fields and properties is preserved in the absence of intervening heap-modifying operations For the non-null dataflow analysis, it is assumed that non-nullness of fields and properties is preserved in the absence of intervening heap-modifying operations Property reads are not considered heap-modifying operations Property reads are not considered heap-modifying operations This is checked at run time because of the possibility of This is checked at run time because of the possibility of Data races Data races Impure property getters Impure property getters Array element types cannot be non-null Array element types cannot be non-null

10 ArrayList.Insert Method (Int32, Object) Inserts an element into the ArraryList at the specified index public virtual void Insert(int index, object value); Parameters index The zero-based index at which value should be inserted. value The Object to insert. The value can be a null reference. Exceptions Contracts today Exception Type Condition ArgumentOutOfRangeException index is less than zero. -or- index is greater then Count. NotSupportedException The ArrayList is read-only. -or- The ArrayList had a fixed size.

11 Preconditions Public virtual void Insert(int index, object value) requires 0 <= index && index <= Count; requires 0 <= index && index <= Count; requires !IsReadOnly && !IsFixedSize; requires !IsReadOnly && !IsFixedSize; { … } { … } Run-time checks are inserted by the compiler to validate that preconditions hold Run-time checks are inserted by the compiler to validate that preconditions hold RequiresViolationExecption is the default exception RequiresViolationExecption is the default exception

12 Otherwise clauses Public virtual void Insert(int index, object value) requires 0 <= index && index <= Count; requires 0 <= index && index <= Count; otherwise ArgumentOutOfRangeException requires !IsReadOnly && !IsFixedSize; requires !IsReadOnly && !IsFixedSize; otherwise NotSupportedException { … } { … } Otherwise clause used to specify what happens when requirements are not met in runtime Otherwise clause used to specify what happens when requirements are not met in runtime

13 Postconditions Public virtual void Insert(int index, object value) ensures Count == old(Count) +1 ensures value == this[index]; ensures Forall { int i in 0 : index; old(this[i]) == this[i] }; ensures Forall { int i in index : old(Count); old(this[i]) == this[i] }; old(this[i]) == this[i] }; Static verification is attempted first Static verification is attempted first Run-time checks inserted by compiler, when required, to check that preconditions hold Run-time checks inserted by compiler, when required, to check that preconditions hold EnsuresViolationExecption is the default exception of a postcondition failure EnsuresViolationExecption is the default exception of a postcondition failure

14 Exceptional Postconditions void ReadToken(ArrayList a) throws EndOfFileException ensures a.Count == old(a.Count) Exceptions that can legally occur can be part of a the method contract Exceptions that can legally occur can be part of a the method contract Can be used only for exceptions that appear in the throws set Can be used only for exceptions that appear in the throws set Can be used only for checked exceptions Can be used only for checked exceptions

15 Inheriting contracts Method contracts can be inherited Method contracts can be inherited Postconditions can be added Postconditions can be added No changes allowed for preconditions No changes allowed for preconditions Interface methods can also have specifications Interface methods can also have specifications Multiple inheritance raises problem of combining contracts Multiple inheritance raises problem of combining contracts Preconditions can be combined only if they are the same Preconditions can be combined only if they are the same Otherwise, only explicit interface method implementation allowed Otherwise, only explicit interface method implementation allowed interface I { void M(int x) requires x <= 10; } class C : I,J { void I.M(int x) {…} void J.M(int x) {…} }

16 0. When do invariants hold? class Car { int speed; int windResistance; invariant windResistance == K * speed * speed; public Car() { speed = 0; windResistance = 0; } public void SetSpeed(int kmph) { speed = kmph; windResistance = K * speed * speed; }

17 0. When do invariants hold? class Car { int speed; int windResistance; invariant windResistance == K * speed * speed; public Car() { speed = 0; windResistance = 0; } public void SetSpeed(int kmph) { speed = kmph; windResistance = K * speed * speed; }

18 When do invariants hold? class Car { int speed; int windResistance; invariant windResistance == K * speed * speed; public Car() { speed = 0; windResistance = 0; } public void SetSpeed(int kmph) { speed = kmph; P( ); windResistance = K * speed * speed; } Invariant temporarily violated —what if P calls back?

19 Object states Mutable Mutable Object invariant might be violated Object invariant might be violated Field updates are allowed Field updates are allowed Valid Valid Object invariant holds Object invariant holds Field updates not allowed Field updates not allowed

20 The heap (the object store)

21 Mutable Valid

22 To mutable and back: expose class Car { int speed; int windResistance; invariant windResistance == K * speed * speed; … public void SetSpeed(int kmph) requires this.valid; { expose (this) { speed = kmph; windResistance = K * speed * speed; } } changes this from valid to mutable changes this from mutable to valid can update speed, because this.mutable

23 Summary for simple objects: (  o o.mutable  Inv(o)) x.f = E; check x.mutable invariant … this.f …; o.mutable  ¬ o.valid

24 Summary for simple objects: (  o o.mutable  Inv(o)) expose (x) { … } x.valid := falsex.valid := true check x.validcheck Inv(x) o.mutable  ¬ o.valid

25 Aggregate objects class Seat { public void Move(int pos) requires this.valid; … } class Car { Seat s; public void Adjust(Profile p) requires this.valid  p.valid; { s.Move(p.SeatPosition); }

26 Ownership Points to owner

27 Ownership domains Points to owner

28 Ownership domains Points to owner x y z x owns y and z y and z are components in the representation of x y and z are peers

29 Points to owner Mutable object Valid object An object is only as valid as its components

30 Representation (rep) fields class Seat { public void Move(int pos) requires this.Consistent; … } class Car { rep Seat s; public void Adjust(Profile p) requires this.Consistent  p.Consistent; { expose (this) { s.Move(p.SeatPosition); } } o.Consistent  o.owner.mutable  o.valid

31 Peer fields and peer validity class Seat { public void Move(int pos) requires this.PeerConsistent; … } class Car { rep Seat s;peer Seat s; public void Adjust(Profile p)public void Adjust(Position p) requires this.PeerConsistent  requiresthis.PeerConsistent  p.PeerConsistent; p.PeerConsistent; {{ expose (this) { s.Move(p.SeatPosition);s.Move(p.SeatPosition); } }} o.Consistent  o.owner.mutable  o.valid o.PeerConsistent  o.owner.mutable  (  p p.owner = o.owner  p.valid)

32 Summary for aggregate objects: (  o o.mutable  Inv(o)) x.f = E; check x.mutable rep T t; invariant … this.t.f …; (  o o.mutable  o.owner.mutable)

33 x.valid := false Summary for aggregate objects: expose (x) { … } x.valid := true check x.valid check x.owner.mutable check (  r r.owner=x  r.valid) check Inv(x) (  o o.mutable  Inv(o)) (  o o.mutable  o.owner.mutable)

34 Immutable types Immutable types class String { String SubString(int st, int len) requires this.PeerConsistent; … } class Car { String serialNumber; public String Year() requires this.PeerConsistent; { return serialNumber.Substring(12, 4); } Note: cannot use rep, since Car cannot expect to be the sole owner

35 Points to owner Mutable object Valid object Immutable object Ever-peer-consistent (immutable) objects

36 Summary for immutable types: (  o Immutable(typeof(o))  o.PeerConsistent) x.f = E; check x.mutable [Immutable] class M { T f; … } class C { M m; invariant … this.m.f …;

37 x.valid := false Summary for immutable types: expose (x) { … } x.valid := true check ¬ Immutable(typeof( x)) check … check … (  o Immutable(typeof(o))  o.PeerConsistent)

38 Immutable is determined from static type (except for object) [Immutable] class C extends B { … } [Immutable] allowed on C if either [Immutable] allowed on C if either B is [Immutable] or B is [Immutable] or B is object B is object [Immutable] required on C if [Immutable] required on C if B is [Immutable] B is [Immutable]

39 Subclasses class Car { int speed; invariant 0 ≤ speed; … } class LuxuryCar extends Car { Radio r; invariant 6 ≤ r.CDCapacity; … }

40 Owners are pairs To support subclasses with invariants, we change owners to be pairs: To support subclasses with invariants, we change owners to be pairs: (object reference, class frame)

41 Invariants and subclasses class A { … } class B extends A { … } Points to owner Object A B

42 Summary for subclasses: (  o,T (o,T).mutable  Inv T (o)) x.f = E; check (x,C).mutable class C extends B { F f; invariant … this.f …; (  o,T (o,T).mutable  o.owner.mutable)

43 (x,C).valid := false Summary for subclasses: C x; … expose (x) { … } (x,C).valid := true check (x,C).valid check x.owner.mutable check (  r r.owner=(x,C)  (  R (r,R).valid)) check Inv C (x) (  o,T (o,T).mutable  Inv T (o)) (  o,T (o,T).mutable  o.owner.mutable)

44 Thank You ! Sources and Tools can be found at Sources and Tools can be found at http://research.microsoft.com/specsharp

45 Backup Slides

46 Static field initialization class C { … static S ! s ; static T ! t ; static C() { s = new S(…); t = new T(…); } } What if this call re-enters class C? One design choice: Impose a partial order on classes In Spec#: enforce all writes check that static constructor assigns to the static non-null fields do checking at some reads

47 Additive invariants class Car { int speed; … } class LuxuryCar extends Car { Radio r; invariant speed > 60  r.SoundBooster=true; overrides void SetSpeed(int kmph) { expose (this) { base.SetSpeed(kmph); if (speed > 60) { … } } } }

48 An additive frame is only as valid as its subclass frames class A { … } class B extends A { … } Points to owner Mutable object Valid object Object A B

49 Summary for additive invariants: (  o,T (o,T).mutable  Inv T (o)) x.f = E; check (  U U <: B  (o,U).mutable) class B extends A { additive F f; … } class C extends B { invariant … this.f …; (  o,T (o,T).mutable  o.owner.mutable)

50 Summary for additive invariants: (  o,T (o,T).mutable  Inv T (o)) (  o,T (o,T).mutable  o.owner.mutable) (  o,T (o,T).transmut  (o,T).mutable  (  U U <: T  (o,U).transmut)) C x; … additive expose (x) { … } (x,C).valid := true (x,C).transmut := false check (x,C).valid  (  U U <: C  (x,U).transmut) check x.owner.mutable check (  r r.owner=(x,C)  (  R (r,R).valid)) check Inv C (x) ≠ ≠ (x,C).valid := false (x,C).transmut := true

51 Object invariants in Spec# Spec# syntactically checks that invariants are admissible Spec# syntactically checks that invariants are admissible Ownership is specified with the [Owned] attribute Ownership is specified with the [Owned] attribute We first supported only rep ownership relations We first supported only rep ownership relations peer relationships are often useful too peer relationships are often useful too we now use PeerConsistent as the default method precondition we now use PeerConsistent as the default method precondition owners are set automatically on assignments of rep and peer fields owners are set automatically on assignments of rep and peer fields An immutable class/interface is specified with [Immutable] An immutable class/interface is specified with [Immutable] We first supported only additive invariants in Spec# We first supported only additive invariants in Spec# non-additive invariants are easier to work with non-additive invariants are easier to work with non-additive expose is now the default non-additive expose is now the default implementation restriction: no further expose allowed on an object while a non-additive expose is in progress implementation restriction: no further expose allowed on an object while a non-additive expose is in progress Additive methods (those that update the additive fields mentioned in additive invariants) require dynamic dispatch and use precondition Consistent Additive methods (those that update the additive fields mentioned in additive invariants) require dynamic dispatch and use precondition Consistent

52 From Spec#... static int Abs(int x) ensures 0 result == x; ensures 0 result == x; ensures x result == -x; ensures x result == -x; { if (x < 0) x = -x; return x; }

53 …via BoogiePL … procedure Abs(x$in: int) returns ($result: int); ensures 0 $result == x$in; ensures 0 $result == x$in; ensures x$in $result == -x$in; ensures x$in $result == -x$in; { var x1, x2: int, b: bool; entry: x1 := x$in; b := x < 0; goto t, f; entry: x1 := x$in; b := x < 0; goto t, f; t: assume b; x := -x; goto end; t: assume b; x := -x; goto end; f: assume !b; goto end; f: assume !b; goto end; end: $result := x; return; } end: $result := x; return; }

54 …via BoogiePL-DSA … procedure Abs(x$in: int) returns ($result: int); ensures 0 $result == x$in; ensures 0 $result == x$in; ensures x$in $result == -x$in; ensures x$in $result == -x$in; { var x1, x2: int, b: bool; entry: x1 := x$in; b := x1 < 0; goto t, f; entry: x1 := x$in; b := x1 < 0; goto t, f; t: assume b; x2 := -x1; goto end; t: assume b; x2 := -x1; goto end; f: assume !b; x2 := x1; goto end; f: assume !b; x2 := x1; goto end; end: $result := x2; return; } end: $result := x2; return; }

55 …via Passive BoogiePL … procedure Abs(x$in: int) returns ($result: int); ensures 0 $result == x$in; ensures 0 $result == x$in; ensures x$in $result == -x$in; ensures x$in $result == -x$in; { var x1, x2: int, b: bool; entry: assume x1 == x$in; entry: assume x1 == x$in; assume b == x1 < 0; goto t, f; assume b == x1 < 0; goto t, f; t: assume b; assume x2 == -x1; goto end; t: assume b; assume x2 == -x1; goto end; f: assume !b; assume x2 == x1; goto end; f: assume !b; assume x2 == x1; goto end; end: assume $result == x2; return; } end: assume $result == x2; return; }

56 … without contracts … procedure Abs(x$in: int) returns ($result: int); ensures 0 $result == x$in; ensures 0 $result == x$in; ensures x$in $result == -x$in; ensures x$in $result == -x$in; { var x1, x2: int, b: bool; entry: assume x1 == x$in; entry: assume x1 == x$in; assume b == x1 < 0; goto t, f; assume b == x1 < 0; goto t, f; t: assume b; assume x2 == -x1; goto end; t: assume b; assume x2 == -x1; goto end; f: assume !b; assume x2 == x1; goto end; f: assume !b; assume x2 == x1; goto end; end: assume $result == x2; return; } end: assume $result == x2; return; }

57 … without contracts … procedure Abs(x$in: int) returns ($result: int); { var x1, x2: int, b: bool; entry: assume x1 == x$in; entry: assume x1 == x$in; assume b == x1 < 0; goto t, f; assume b == x1 < 0; goto t, f; t: assume b; assume x2 == -x1; goto end; t: assume b; assume x2 == -x1; goto end; f: assume !b; assume x2 == x1; goto end; f: assume !b; assume x2 == x1; goto end; end: assume $result == x2; end: assume $result == x2; assert 0 $result == x$in; assert 0 $result == x$in; assert x$in $result == -x$in; assert x$in $result == -x$in; return; } return; }

58 …to Logic [M. Barnett, K. R. M. Leino, in preparation] entry && entry && (entry (entry b == x1 t && f)) && b == x1 t && f)) && (t x2 == -x1 ==> end)) && (t x2 == -x1 ==> end)) && (f x2 == x1 ==> end)) && (f x2 == x1 ==> end)) && (end (end (0 $result == x$in) && (0 $result == x$in) && (x$in $result == -x$in) && (x$in $result == -x$in) && true)) true))


Download ppt "Introduction to Spec# Programming System Yossi Peery Advanced SW Tools Seminar TAU Nov 2006."

Similar presentations


Ads by Google