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

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

  • View
    222

  • Download
    0

Embed Size (px)

Citation preview

Introduction to Spec# Introduction to Spec# Programming SystemProgramming System

Yossi PeeryYossi PeeryAdvanced SW Tools Seminar Advanced SW Tools Seminar TAU Nov 2006TAU Nov 2006

Spec#Spec#

Spec# = C# + contractsSpec# = C# + contracts 3 levels of checking3 levels of checking

static type checkingstatic type checking runtime checkingruntime checking program verificationprogram verification

Boogie verifierBoogie verifier Simplify theorem proverSimplify theorem prover

Tool support integrated with MS Visual Tool support integrated with MS Visual StudioStudio

Non-null typesNon-null types

Each reference type Each reference type TT includes the includes the value value nullnull

Spec#’s type Spec#’s type T!T! contains only contains only references to objects of type references to objects of type TT (not(not nullnull).).

Types versus AssertionsTypes versus Assertions

Without non-null types:Without non-null types:Person(Person(stringstring name) name) requiresrequires name != name != nullnull;;

With non-null types:With non-null types:Person(Person(string/*^string/*^!^*/ name)!^*/ name)

[Q] What is the difference?[Q] What is the difference?

Non-null types are flow-Non-null types are flow-sensitivesensitive

The non-null type of an expression is flow-sensitive. The non-null type of an expression is flow-sensitive.

voidvoid Foo(T o) { Foo(T o) { ifif (o != (o != nullnull)) T! p = o; T! p = o; // OK// OK!!}}

That is, it does not follow uniquely from the declared types of That is, it does not follow uniquely from the declared types of the variables and members mentioned in the expression.the variables and members mentioned in the expression.

Non-null Fields and Object Non-null Fields and Object CreationCreation

abstract classabstract class C { C { publicpublic C() { C() { thisthis.M(); }.M(); } public abstract intpublic abstract int M(); M();}}

classclass D : C { D : C { T! f;T! f; D(T! x) : D(T! x) : basebase() {() { f = x;f = x; }} public override intpublic override int M{ M{ returnreturn

f.g; }f.g; }}}

classclass D : C { D : C { T! f;T! f; D(T! x) { D(T! x) { f = x;f = x;

basebase() () }} public override intpublic override int M{ M{ returnreturn

f.g; }f.g; }}}

Non-nullness of FieldsNon-nullness of Fields

Common coding pattern:Common coding pattern:

ifif (o.f != (o.f != nullnull))

o.f.Foo();o.f.Foo();

[Q] How can this go wrong?[Q] How can this go wrong?

Non-nullness of PropertiesNon-nullness of Properties

Common coding pattern:Common coding pattern:

ifif (o.P != (o.P != nullnull))

o.P.Foo();o.P.Foo();

[Q] How can this go wrong?[Q] How can this go wrong?

Fields and PropertiesFields and Properties

For the non-null dataflow analysis, it is assumed For the non-null dataflow analysis, it is assumed that non-nullness of fields and properties is that non-nullness of fields and properties is preserved in the absence of intervening heap-preserved in the absence of intervening heap-modifying operationsmodifying operations

Property reads are not considered heap-Property reads are not considered heap-modifying operationsmodifying operations

This is checked at run time because of the This is checked at run time because of the possibility ofpossibility of Data racesData races Impure property gettersImpure property getters

Array element types cannot be non-nullArray element types cannot be non-null

ArrayList.Insert Method (Int32, Object)Inserts an element into the ArraryList at the specified index

public virtual void Insert(int index, object value);

Parameters

indexThe zero-based index at which value should be inserted.

valueThe Object to insert. The value can be a null reference.

Exceptions

Contracts todayContracts today

Exception TypeException TypeConditionCondition

ArgumentOutOfRangeExcepArgumentOutOfRangeExceptiontion

indexindex is less than zero. is less than zero.

-or--or-

indexindex is greater then Count. is greater then Count.

NotSupportedExceptionNotSupportedExceptionThe The ArrayListArrayList is read-only. is read-only.

-or--or-

The The ArrayListArrayList had a fixed size. had a fixed size.

PreconditionsPreconditionsPublic virtual voidPublic virtual void Insert( Insert(intint index, index, objectobject value) value)

requiresrequires 0 <= index && index <= Count; 0 <= index && index <= Count;

requiresrequires !IsReadOnly && !IsFixedSize;!IsReadOnly && !IsFixedSize;

{ … }{ … } Run-time checks are inserted by the compiler to validate Run-time checks are inserted by the compiler to validate

that preconditions holdthat preconditions holdRequiresViolationExecptionRequiresViolationExecption is the default exception is the default exception

Otherwise clausesOtherwise clauses

Public virtual voidPublic virtual void Insert( Insert(intint index, index, objectobject value) value)

requiresrequires 0 <= index && index <= Count; 0 <= index && index <= Count;

otherwiseotherwise ArgumentOutOfRangeException ArgumentOutOfRangeException

requiresrequires !IsReadOnly && !IsFixedSize;!IsReadOnly && !IsFixedSize;

otherwiseotherwise NotSupportedException NotSupportedException

{ … }{ … } Otherwise clause used to specify what happens when Otherwise clause used to specify what happens when requirements are not met in runtimerequirements are not met in runtime

PostconditionsPostconditionsPublic virtual voidPublic virtual void Insert( Insert(intint index, index, objectobject value) value)

ensures ensures Count == Count == oldold(Count) +1(Count) +1

ensures ensures value == value == thisthis[index];[index];

ensuresensures ForallForall { { intint i i inin 0 : index; 0 : index; oldold((thisthis[i]) == [i]) == thisthis[i] };[i] };

ensuresensures ForallForall { { intint i i inin index : index : oldold(Count);(Count);

oldold((thisthis[i]) == [i]) == thisthis[i] };[i] };

Static verification is attempted firstStatic verification is attempted first Run-time checks inserted by compiler, when required, to check that preconditions Run-time checks inserted by compiler, when required, to check that preconditions

holdhold EnsuresViolationExecptionEnsuresViolationExecption is the default exception of a postcondition failure is the default exception of a postcondition failure

Exceptional PostconditionsExceptional Postconditionsvoidvoid ReadToken(ArrayList a) ReadToken(ArrayList a)

throwsthrows EndOfFileException EndOfFileException ensuresensures a.Count == a.Count == oldold(a.Count)(a.Count)

Exceptions that can legally occur can be part of a the method Exceptions that can legally occur can be part of a the method contractcontract

Can be used only for exceptions that appear in the throws setCan be used only for exceptions that appear in the throws set Can be used only for checked exceptionsCan be used only for checked exceptions

Inheriting contractsInheriting contracts Method contracts can be inheritedMethod contracts can be inherited

Postconditions can be addedPostconditions can be added No changes allowed for preconditionsNo changes allowed for preconditions

Interface methods can also have specificationsInterface methods can also have specifications Multiple inheritance raises problem of combining Multiple inheritance raises problem of combining

contractscontracts Preconditions can be combined only if they are the samePreconditions can be combined only if they are the same Otherwise, only explicit interface method implementation Otherwise, only explicit interface method implementation

allowedallowed

interfaceinterface I { I { voidvoid M( M(intint x) x) requiresrequires x <= 10; } x <= 10; }interfaceinterface I { I { voidvoid M( M(intint x) x) requiresrequires x <= 10; } x <= 10; }classclass C : I,J { C : I,J {

voidvoid I.M(I.M(intint x) {…} x) {…}voidvoid J.M( J.M(intint x) {…} x) {…}

}}

0. When do invariants hold?0. When do invariants hold?classclass Car { Car {

intint speed; speed;intint windResistance; windResistance;

invariantinvariant windResistance == K * speed * speed; windResistance == K * speed * speed;

publicpublic Car() { speed = Car() { speed = 0; windResistance = 0; windResistance = 0; }0; }

publicpublic voidvoid SetSpeed( SetSpeed(intint kmph) { kmph) {speed = speed = kmph;kmph;windResistance = windResistance = K * speed * speed;K * speed * speed;

}}

0. When do invariants hold?0. When do invariants hold?classclass Car { Car {

intint speed; speed;intint windResistance; windResistance;

invariantinvariant windResistance == K * speed * speed; windResistance == K * speed * speed;

publicpublic Car() { speed = Car() { speed = 0; windResistance = 0; windResistance = 0; }0; }

publicpublic voidvoid SetSpeed( SetSpeed(intint kmph) { kmph) {speed = speed = kmph;kmph;windResistance = windResistance = K * speed * speed;K * speed * speed;

}}

When do invariants hold?When do invariants hold?classclass Car { Car {

intint speed; speed;intint windResistance; windResistance;

invariantinvariant windResistance == K * speed * speed; windResistance == K * speed * speed;

publicpublic Car() { speed = Car() { speed = 0; windResistance = 0; windResistance = 0; }0; }

publicpublic voidvoid SetSpeed( SetSpeed(intint kmph) { kmph) {speed = speed = kmph; P(kmph; P( ););windResistance = windResistance = K * speed * speed;K * speed * speed;

}}Invariant

temporarilyviolated

—what if Pcalls back?

Object statesObject states

MutableMutable Object invariant might be violatedObject invariant might be violated Field updates are allowedField updates are allowed

ValidValid Object invariant holdsObject invariant holds Field updates not allowedField updates not allowed

The heap (the object store)The heap (the object store)

The heap (the object store)The heap (the object store)

MutableValid

To mutable and back: To mutable and back: exposeexpose

classclass Car { Car {intint speed; speed;intint windResistance; windResistance;invariantinvariant windResistance == K * speed * speed; windResistance == K * speed * speed;……publicpublic voidvoid SetSpeed( SetSpeed(intint kmph) kmph)

requiresrequires thisthis.valid;.valid;{{

exposeexpose ( (thisthis) {) {speed = speed = kmph;kmph;windResistance = windResistance = K * speed * speed;K * speed * speed;

}}}}

changes thisfrom valid to mutable

changes thisfrom mutable to valid

can update speed,because this.mutable

Summary for simple objects:Summary for simple objects:

((o • o.mutable o • o.mutable Inv(o)) Inv(o))

x.f = E;x.f = E;check x.mutable

invariantinvariant … … thisthis.f …;.f …;

o.mutable ¬ o.valid

Summary for simple objects:Summary for simple objects:

((o • o.mutable o • o.mutable Inv(o)) Inv(o))

exposeexpose (x) { … } (x) { … }x.valid := false x.valid := true

check x.valid check Inv(x)

o.mutable ¬ o.valid

Aggregate objectsAggregate objectsclassclass Seat { Seat { publicpublic voidvoid Move( Move(intint pos) pos) requiresrequires

thisthis.valid; … }.valid; … }

classclass Car { Car {

Seat s;Seat s;

publicpublic voidvoid Adjust(Profile p) Adjust(Profile p)requiresrequires thisthis.valid .valid p.valid; p.valid;

{{s.Move(p.SeatPosition);s.Move(p.SeatPosition);

}}

OwnershipOwnership

Points to owner

Ownership domainsOwnership domains

Points to owner

Ownership domainsOwnership domains

Points to owner

x

y z

x owns y and z

y and z are componentsin the representation of x

y and z are peers

Points to ownerMutable objectValid object

An object is only as valid as its componentsAn object is only as valid as its components

Representation (rep) fieldsRepresentation (rep) fieldsclassclass Seat { Seat { publicpublic voidvoid Move( Move(intint pos) pos) requiresrequires thisthis.Consistent; … }.Consistent; … }

classclass Car { Car {

reprep Seat s; Seat s;

publicpublic voidvoid Adjust(Profile p) Adjust(Profile p)requiresrequires thisthis.Consistent .Consistent p.Consistent; p.Consistent;

{{exposeexpose ( (thisthis) {) {

s.Move(p.SeatPosition);s.Move(p.SeatPosition);}}

}}

o.Consistent o.owner.mutable o.valid

Peer fields and peer validityPeer fields and peer validityclassclass Seat { Seat { publicpublic voidvoid Move( Move(intint pos) pos) requiresrequires thisthis.PeerConsistent; … }.PeerConsistent; … }

classclass Car { Car {

reprep Seat s; Seat s; peerpeer Seat s; Seat s;

publicpublic voidvoid Adjust(Profile p) Adjust(Profile p) publicpublic voidvoid Adjust(Position p) Adjust(Position p)requiresrequires thisthis.PeerConsistent .PeerConsistent

requiresrequires thisthis.PeerConsistent .PeerConsistent p.PeerConsistent; p.PeerConsistent; p.PeerConsistent; p.PeerConsistent;

{{ {{exposeexpose ( (thisthis) {) {

s.Move(p.SeatPosition);s.Move(p.SeatPosition); 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)

Summary for aggregate objects:Summary for aggregate objects:

((o • o.mutable o • o.mutable Inv(o)) Inv(o))

x.f = E;x.f = E;check x.mutable

rep rep TT t;t;invariantinvariant … … thisthis.t.f …;.t.f …;

((o • o.mutable o • o.mutable o.owner.mutable) o.owner.mutable)

x.valid := false

Summary for aggregate objects:Summary for aggregate objects:

exposeexpose (x) { … } (x) { … }x.valid := true

check x.validcheck x.owner.mutable

check (r • r.owner=x r.valid)check Inv(x)

((o • o.mutable o • o.mutable Inv(o)) Inv(o))((o • o.mutable o • o.mutable o.owner.mutable) o.owner.mutable)

Immutable typesImmutable types

class class String {String {String SubString(String SubString(intint st, st, intint len) len) requiresrequires thisthis.PeerConsistent;.PeerConsistent;… }… }

classclass Car { Car {

String serialNumber;String serialNumber;

publicpublic String Year() String Year()requiresrequires thisthis.PeerConsistent;.PeerConsistent;

{{returnreturn serialNumber.Substring(12, 4); serialNumber.Substring(12, 4);

}}

Note: cannotuse rep,since Car

cannot expectto be the

sole owner

Points to ownerMutable objectValid objectImmutable object

Ever-peer-consistent (immutable) Ever-peer-consistent (immutable) objectsobjects

Summary for immutable types:Summary for immutable types:((o • Immutable(typeof(o)) o • Immutable(typeof(o))

o.PeerConsistent)o.PeerConsistent)

x.f = E;x.f = E;check x.mutable

[Immutable][Immutable] class class M { TM { T f; f; … }… }

class class C {C {MM m;m;invariantinvariant … … thisthis.m.f …;.m.f …;

x.valid := false

Summary for immutable types:Summary for immutable types:

exposeexpose (x) { … } (x) { … }x.valid := true

check ¬ Immutable(typeof(x))check …

check …

((o • Immutable(typeof(o)) o • Immutable(typeof(o)) o.PeerConsistent)o.PeerConsistent)

Immutable is determined from Immutable is determined from static type (except for static type (except for objectobject))

[Immutable] [Immutable] classclass C C extendsextends B { … B { … }}

[Immutable] allowed on C if either[Immutable] allowed on C if either B is [Immutable] orB is [Immutable] or B is B is objectobject

[Immutable] required on C if[Immutable] required on C if B is [Immutable]B is [Immutable]

SubclassesSubclassesclassclass Car { Car {

intint speed; speed;invariantinvariant 0 ≤ speed; 0 ≤ speed;……

}}

classclass LuxuryCar LuxuryCar extendsextends Car { Car {Radio r;Radio r;invariantinvariant 6 ≤ r.CDCapacity; 6 ≤ r.CDCapacity;……

}}

Owners are pairsOwners are pairs

To support subclasses with To support subclasses with invariants, we change owners to be invariants, we change owners to be pairs:pairs:

(object reference, class frame)(object reference, class frame)

Invariants and subclassesInvariants and subclasses

class A { … }

class B extends A { … }

Points to owner

Object

A

B

Summary for subclasses:Summary for subclasses:

((o,T • (o,T).mutable o,T • (o,T).mutable Inv InvTT(o))(o))

x.f = E;x.f = E;check (x,C).mutable

class class C C extendsextends B { B { F F f;f; invariantinvariant … … thisthis.f …;.f …;

((o,T • (o,T).mutable o,T • (o,T).mutable o.owner.mutable) o.owner.mutable)

(x,C).valid := false

Summary for subclasses:Summary for subclasses:

CC x; …x; …exposeexpose (x) { … } (x) { … }

(x,C).valid := true

check (x,C).validcheck x.owner.mutable

check (r • r.owner=(x,C) (R • (r,R).valid))check InvC(x)

((o,T • (o,T).mutable o,T • (o,T).mutable Inv InvTT(o))(o))((o,T • (o,T).mutable o,T • (o,T).mutable o.owner.mutable) o.owner.mutable)

Thank You !Thank You !

Sources and Tools can be found atSources and Tools can be found athttp://research.microsoft.com/specsharphttp://research.microsoft.com/specsharp

Backup SlidesBackup Slides

Static field initializationStatic field initialization

classclass C { C {……staticstatic S ! s ; S ! s ;staticstatic T ! t ; T ! t ;staticstatic C() { C() {

s = s = newnew S(…); S(…);t = t = newnew T(…); T(…);

}}}}

What if this callre-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

Additive invariantsAdditive invariantsclassclass Car { Car {

intint speed; speed;……

}}classclass LuxuryCar LuxuryCar extendsextends Car { Car {

Radio r;Radio r;invariantinvariant speed > 60 speed > 60 r.SoundBooster= r.SoundBooster=truetrue;;overridesoverrides voidvoid SetSpeed( SetSpeed(intint kmph) { kmph) {

exposeexpose ( (thisthis) {) {basebase.SetSpeed(kmph);.SetSpeed(kmph);ifif (speed > 60) { … } (speed > 60) { … }

}}}}

}}

An additive frame is only as An additive frame is only as valid as its subclass framesvalid as its subclass frames

class A { … }

class B extends A { … }

Points to ownerMutable objectValid object

Object

A

B

Summary for additive invariants:Summary for additive invariants:

((o,T • (o,T).mutable o,T • (o,T).mutable Inv InvTT(o))(o))

x.f = E;x.f = E;check (U • U <: B (o,U).mutable)

classclass B B extends extends A {A { additive additive F f; F f; … }… }class class C C extendsextends B { B { invariantinvariant … … thisthis.f …;.f …;

((o,T • (o,T).mutable o,T • (o,T).mutable o.owner.mutable) o.owner.mutable)

Summary for additive invariants:Summary for additive invariants:((o,T • (o,T).mutable o,T • (o,T).mutable Inv InvTT(o))(o))((o,T • (o,T).mutable o,T • (o,T).mutable o.owner.mutable) o.owner.mutable)

((o,T • (o,T).transmut o,T • (o,T).transmut (o,T).mutable (o,T).mutable ((U • U <: T U • U <: T (o,U).transmut)) (o,U).transmut))

CC x; …x; …additiveadditive exposeexpose (x) { … } (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 InvC(x)

(x,C).valid := false(x,C).transmut :=

true

Object invariants in Spec#Object invariants in Spec# Spec# syntactically checks that invariants are admissibleSpec# syntactically checks that invariants are admissible Ownership is specified with the [Owned] attributeOwnership is specified with the [Owned] attribute We first supported only We first supported only reprep ownership relations ownership relations

peerpeer relationships are often useful too relationships are often useful too we now use we now use PeerConsistent PeerConsistent as the default method preconditionas the default method precondition owners are set automatically on assignments of owners are set automatically on assignments of reprep and and peerpeer fields 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 withnon-additive invariants are easier to work with non-additive expose is now the defaultnon-additive expose is now the default implementation restriction: no further expose allowed on an object implementation restriction: no further expose allowed on an object

while a non-additive expose is in progresswhile a non-additive expose is in progress Additive methods (those that update the additive fields Additive methods (those that update the additive fields

mentioned in additive invariants) require dynamic dispatch mentioned in additive invariants) require dynamic dispatch and use precondition and use precondition ConsistentConsistent

From Spec#...From Spec#...

static intstatic int Abs( Abs(intint x) x)

ensuresensures 0 <= x ==> 0 <= x ==> resultresult == x; == x;

ensuresensures x < 0 ==> x < 0 ==> resultresult == -x; == -x;

{ { ifif (x < 0) x = -x; (x < 0) x = -x; returnreturn x; } x; }

……via BoogiePL …via BoogiePL …

procedureprocedure Abs(x$in: Abs(x$in: intint) ) returnsreturns ($result: ($result: intint);); ensuresensures 0 <= x$in ==> $result == x$in; 0 <= x$in ==> $result == x$in; ensuresensures x$in < 0 ==> $result == -x$in; x$in < 0 ==> $result == -x$in;{ { varvar x x1, x21, x2: : intint, b: , b: boolbool;;

entry: xentry: x11 := x$in; b := x < 0; := x$in; b := x < 0; gotogoto t, f; t, f; t: t: assumeassume b; x := -x; b; x := -x; gotogoto end; end; f: f: assumeassume !b; !b; gotogoto end; end; end: end: $result := x; $result := x; returnreturn; }; }

……via BoogiePL-DSA …via BoogiePL-DSA …

procedureprocedure Abs(x$in: Abs(x$in: intint) ) returnsreturns ($result: ($result: intint);); ensuresensures 0 <= x$in ==> $result == x$in; 0 <= x$in ==> $result == x$in; ensuresensures x$in < 0 ==> $result == -x$in; x$in < 0 ==> $result == -x$in;{ { varvar x1, x2: x1, x2: intint, b: , b: boolbool;;

entry: x1 := x$in; b := x1 < 0; entry: x1 := x$in; b := x1 < 0; gotogoto t, f; t, f; t: t: assumeassume b; x2 := -x1; b; x2 := -x1; gotogoto end; end; f: f: assumeassume !b; x2 := x1; !b; x2 := x1; gotogoto end; end; end: $result := x2; end: $result := x2; returnreturn; }; }

……via Passive BoogiePL …via Passive BoogiePL …procedureprocedure Abs(x$in: Abs(x$in: intint) ) returnsreturns ($result: ($result: intint);); ensuresensures 0 <= x$in ==> $result == x$in; 0 <= x$in ==> $result == x$in; ensuresensures x$in < 0 ==> $result == -x$in; x$in < 0 ==> $result == -x$in;{ { varvar x1, x2: x1, x2: intint, b: , b: boolbool;;

entry: entry: assumeassume x1 == x$in; x1 == x$in; assumeassume b == x1 < 0; b == x1 < 0; gotogoto t, f; t, f; t: t: assumeassume b; b; assumeassume x2 == -x1; x2 == -x1; gotogoto end; end; f: f: assumeassume !b; !b; assumeassume x2 == x1; x2 == x1; gotogoto end; end; end: end: assumeassume $result == x2; $result == x2; returnreturn; }; }

… … without contracts …without contracts …procedureprocedure Abs(x$in: Abs(x$in: intint) ) returnsreturns ($result: ($result: intint);); ensuresensures 0 <= x$in ==> $result == x$in; 0 <= x$in ==> $result == x$in; ensuresensures x$in < 0 ==> $result == -x$in; x$in < 0 ==> $result == -x$in;{ { varvar x1, x2: x1, x2: intint, b: , b: boolbool;;

entry: entry: assumeassume x1 == x$in; x1 == x$in; assumeassume b == x1 < 0; b == x1 < 0; gotogoto t, f; t, f; t: t: assumeassume b; b; assumeassume x2 == -x1; x2 == -x1; gotogoto end; end; f: f: assumeassume !b; !b; assumeassume x2 == x1; x2 == x1; gotogoto end; end; end: end: assumeassume $result == x2; $result == x2; returnreturn; }; }

… … without contracts …without contracts …procedureprocedure Abs(x$in: Abs(x$in: intint) ) returnsreturns ($result: ($result: intint););{ { varvar x1, x2: x1, x2: intint, b: , b: boolbool;;

entry: entry: assumeassume x1 == x$in; x1 == x$in; assumeassume b == x1 < 0; b == x1 < 0; gotogoto t, f; t, f; t: t: assumeassume b; b; assumeassume x2 == -x1; x2 == -x1; gotogoto end; end; f: f: assumeassume !b; !b; assumeassume x2 == x1; x2 == x1; gotogoto end; end; end: end: assumeassume $result == x2; $result == x2; assertassert 0 <= x$in ==> $result == x$in; 0 <= x$in ==> $result == x$in; assertassert x$in < 0 ==> $result == -x$in; x$in < 0 ==> $result == -x$in;

returnreturn; }; }

……to Logicto Logic[M. Barnett, K. R. M. Leino, in preparation][M. Barnett, K. R. M. Leino, in preparation]

entry &&entry && (entry <== (x1 == x$in ==>(entry <== (x1 == x$in ==> b == x1 < 0 ==> t && f)) b == x1 < 0 ==> t && f))

&&&& (t <== (b ==> x2 == -x1 ==> end)) (t <== (b ==> x2 == -x1 ==> end))

&&&& (f <== (!b ==> x2 == x1 ==> end)) (f <== (!b ==> x2 == x1 ==> end))

&&&& (end <== ($result == x2 ==>(end <== ($result == x2 ==> (0 <= x$in ==> $result == x$in) &&(0 <= x$in ==> $result == x$in) && (x$in < 0 ==> $result == -x$in) &&(x$in < 0 ==> $result == -x$in) && truetrue))))