invariantes - dc.uba.ar · se verifica que vale a la salida del método – ... /*@ nullable @*/...

60
 Invariantes

Upload: truongdat

Post on 24-May-2018

219 views

Category:

Documents


1 download

TRANSCRIPT

   

Invariantes

   

¿Qué es un invariante?

● Un invariante es un predicado que especifica qué estados de un objeto son consistentes.

   

1er Semántica

● Un invariante es una propiedad que SIEMPRE tiene que cumplir un objeto

   

Ejemplo

class Counter {   int c;   boolean even;   //@ invariant even <==> c%2==0

   void inc() {     c++;     if (c%2==0)        even=true;     else        even=false;   }}

el invariante nose cumple

● La semántica es muy restrictiva

   

2da Semántica

● Un invariante es una propiedad que :● Se asume que vale a la entrada del método 

– (ímplicitamente incluida en la precondición)● Se verifica que vale a la salida del método 

– (ímplicitamente incluida en la postcondición)

● ¿ Es la noción de invariante realmente necesaria?

   

Noción de invarianteclass C_INV {  //@ invariant INV(this)

  //@ requires ...  //@ ensures ...  M1() {...}

  //@ requires ...  //@ ensures ...  M2() {...}}

class C_NO_INV {

  //@ requires INV(this) && ...  //@ ensures INV(this) && ...  M1() {...}

  //@ requires INV(this) && ...  //@ ensures INV(this) && ...  M2() {...}}

● ¿ Son equivalentes ?

   

Noción de invariante

class C {  //@ invariant INV(this)

  //@ requires ...  //@ ensures ...  M1() {...}

  //@ requires ...  //@ ensures ...  M2() {...}}

class C {

  //@ requires INV(this) && ...  //@ ensures INV(this) && ...  M1() {...}

  //@ requires INV(this) && ...  //@ ensures INV(this) && ...  M2() {...}}

clase C_INV clase C_NO_INV

subclase C_INVsubclase 

C_NO_INV

● Las subclases no son equivalentes● Se pierde la noción que la estructura debe 

cumplir el invariante

extiende extiende

   

Ejemploclass List {  //@ invariant size>=0;  public int size;  ....  M() {...}}

class ListClient {  //@ invariant INV_ListClient(this);

  void buggy(List list) {    list.size = ­1;  }  ...

class List {

  public int size;  ....  //@ requires size>=0;  //@ ensures size>=0;  M(){...}}

class ListClient {

  //@ requires INV_ListClient(this);  //@ ensures INV_ListClient(this);  void buggy(List list) {    list.size = ­1;  }  ...

   

Ejemplo

class List {

  public int size;  ....  //@ requires size>=0;  //@ ensures size>=0;  M(){...}}

class ListClient {

  //@ requires INV_ListClient(this);  //@ ensures INV_ListClient(this);  void buggy(List list) {    list.size = ­1;  }  ...

● Todos los métodos preservan el invariante de cada clase.

● Sin embargo, el método buggy rompe el invariante de la clase List

   

3er Semántica

● Un invariante es una propiedad que tiene que valer en todos los estados visibles de un objeto.

● ¿Qué es un estado visible?● El pre­estado y el post­estado de una invocación a 

un método

   

● Al verificar un método M● asumo que vale el invariante de todos los objetos● tengo que probar que vale el invariante de todos los 

objetos

   

Invariantes en ESC/Java2

● Verificar el invariante de TODOS los objetos es muy costoso

● ESC/Java2 verifica los invariantes de ALGUNOS objetos● Ejemplo: objetos que pertenezcan a clases usadas

Semántica JML

pre for all Object o ;INV(o)post for all Object o; INV(o){...}

Verificación ESC/Java2

pre for some Object o ; INV(o)post for some Object o ; INV(o){...}

¿La pregunta es cuáles son esos objetos ?

   

Errata ESC/Java2

Clase pasada

class SortedLinkedList {

   int i;

   SortedLinkedList next;

   //@ invariant i > next.i;

  public void inc() {

     // vale el invariante de this

     i++;

     // verifica que vale el invariante de this

  }

}

   

Errata ESC/Java2

● escj ­routine inc SortedLinkedList.javaSortedLinkedList.java:13: Warning: 

Possible violation of object invariant (Invariant)

  }

  ^

Associated declaration is "SortedLinkedList.java", line 9, col 6:

  //@ invariant i > next.i;

      ^

   

Errata ESC/Java2

Possibly relevant items from the counterexample context:  

  brokenObj.(i:12.4) == (tmp0!old!i:12.4 + 1)

  brokenObj.(next@pre:5.36) == this

  brokenObj != this

  brokenObj != null

  this.(i:7.6) == tmp0!old!i:12.4

  this.(i:12.4) == (tmp0!old!i:12.4 + 1)

  ....

(brokenObj* refers to the object for which the invariant is broken.)

   

Errata ESC/Java2

nextnext

this

tmp0!old!i:12.4 + 1

brokenObj

....

tmp0!old!i:12.4 + 1

   

Otro ejemploclass Purse {  int money;  //@ invariant money >= 0;}

class RichPerson {

  /*@ nullable @*/ String mansion_address;  /*@ nullable @*/ Purse purse;

  //@ invariant mansion_address!=null;  //@ invariant purse!=null;  //@ invariant purse.money > 10;

  public void earnMoney() {    purse.money = purse.money +1;  }

class PoorPerson {

  /*@ nullable @*/ String slum_address;  /*@ nullable @*/ Purse purse;

  //@ invariant slum_address!=null;  //@ invariant purse!=null;  //@ invariant purse.money < 100;

  //@ requires purse.money > 0;  public void loseMoney() {    purse.money = purse.money ­1;  }

   

Preguntas

● ¿ El método loseMoney es correcto ?

● ¿ Qué comportamiento esperamos de ESC/Java2 ?

   

Posible violación del contrato

RichPersonRichPerson PoorPerson

Purse

money=9

invariant purse.money > 10; invariant purse.money < 100;

RichPersonRichPerson PoorPerson

Purse

money=10

invariant purse.money > 10; invariant purse.money < 100;

loseMoney()

estadoinicial

estadofinal

this

this

   

ESC/Java2

● ESC/Java2 con PoorPerson, RichPerson, PursePoorPerson: loseMoney() ...

    [0.197 s 39390680 bytes]  passed

● ESC/Java2 no encontró el bug :● no analizó si se mantiene o no el invariante de los 

objetos de la clase RichPerson

   

ESC/Java2

public void loseMoney(RichPerson my_friend) {

  purse.money = purse.money ­1;

}

● escj ­routine loseMoney *.javaPoorPerson.java:24: Warning: Possible violation of object invariant (Invariant)

Associated declaration is "RichPerson.java", line 13, col 6:

  //@ invariant purse.money > 10;

   

ESC/Java2 ­ Contraejemplo

Possibly relevant items from the counterexample context:  

  typeof(brokenObj<4>) <: T_RichPerson

  typeof(this) <: T_PoorPerson

  (brokenObj<4>).(purse:7.25) == tmp0!purse:23.4

  this.(purse:7.25) == tmp0!purse:23.4

  (tmp0!purse:23.4).(money@pre:4.3.6) == 11  

  (tmp0!purse:23.4).(money:23.10) == 10

   ....

Agregar un argumento de la clase RichPerson forzó la verificación de sus objetos

   

Ejemplo

class Mapping {

   //@ invariant keys.size()==values.size(); 

   List keys;

   List values; 

   define(Object k, Object v) {

     keys.add(k);  

     /* keys.size()!=values.size() */

     values.add(v);

   }

 } 

   

Restricciones

● La semántica de estados visibles puede ser muy restrictiva.

● En el ejemplo : No me deja actualizar la lista de nodos ● invariante del Mapping no vale en un estado visible

   

Modularidad

● La semántica es altamente no modular :● Al analizar un método

– asumo que valen TODOS los invariantes de todos los objetos alocados a al entrada del método

– tengo probar que valen TODOS los invariantes de todos los objetos alocados a la salida del método

● Ante una invocación a otro método :– tengo que probar que valen TODOS los invariantes de 

todos los objetos alocados antes de invocarlo– asumo que valen TODOS los invaraintes de todos los 

objetos alocados luego de la invocación

   

¿ y la verificación modular ?

● Nos gustaría demostrar invariantes modularmente :● Verificar únicamente el invariante de la clase bajo 

análisis● Preservar por construcción el invariante de las 

otras clases

● Spec# propone una serie de restricciones para lograr esto. 

10/20/09 27

Análisis modular de invariantes en Spec#

● Se introduce campos ghost para poder hablar del estado del invariante

● Se restringen los posibles invariantes que se pueden escribir

● Se debe indicar cuándo el invariante de un objeto puede romperse y cuándo debe reestablecerse

10/20/09 28

Protección de updates• Se introduce un nuevo campo ghost llamado “inv”

– Los valores posibles de este campo son { Mutable, Valid }

– No puede ser modificado por el programador sino a través de comandos especiales

• Ahora, los campos de un objeto pueden actualizarse sólo si el objeto está en estado “Mutable”

• Se introduce una nueva estructura de bloque, llamada expose

o.f := e ; assert o.inv=Mutable; o.f := e ;

10/20/09 29

Protocolo expose {...}

void Tick( ) requires this.inv=Valid { expose(this){ c++; even = c%2==0; } X.P(this); }

La semántica del expose, se define como :    expose(o) s; = unpack o; s; pack o;

:Clock  

Valid

Mutable

10/20/09 30

Pack / Unpack

La semántica del expose(o) { Q }, se define como :    unpack o;     Q     pack o;

• unpack(o) convierte al objeto o en mutable• pack(o) reestablece el invariante y convierte al 

objeto o en válidounpack o :

assert o.inv == Valid; o.inv := Mutable

pack o :

assert o.inv = Mutable; assert Inv(o); o.inv := Valid

10/20/09 31

Program Invariant• Estado del heap :         ∀o:  o.inv ≠  mutable ⇒ Inv( o ) 

• Sólo se admiten invariantes que contienen accesos a campos de las forma :– this.f1, this.f2, …

• Ejemplo :– invariant this.c>=0 && this.even <==> this.c

%2==0 ;

10/20/09 32

Problema: estructuras complejas

¿Cómo podemos relajar la restricción sobre invariantes que podemos describir ?

¿Cómo podemos razonar modularmente sobre ambas clases ?

class Person { int freeDay; Meeting next; invariant this.next != null ⇒ this.next.day != freeDay;}

class Meeting { int day; invariant 0 ≤ day<7;

void Reschedule(int d ) requires this.inv=Valid { expose(this){ day = d; } }}

10/20/09 33

Amenazas al invariante de Person

 : Meeting

 : Person

next

next.day != freeDay

 : Foo

bar

bar.day >= 5

call reschedule(4)

10/20/09 34

Amenazas al invariante de Person

 : Meeting

 : Person

next.day != freeDay

 : Foo

bar

bar.day >= 5

call reschedule(4)Modificando la clase

Person puedo romperel invariante de otra 

clase  

Otro objeto puede invocarun método de la claseMeeting que rompa el 

invariante de la clase Person

next

10/20/09 35

Amenazas al invariante de Person

 : Meeting

 : Person

next.day != freeDay

 : Foo

bar

bar.day >= 5

call reschedule(4)

Quiero no restringirel aliasing de Foo

next

10/20/09 36

Protocolo expose con ownership

 : Meeting

 : Person

next.day != freeDay

owner

Valid

Mutable

Committed

inv = 

next

10/20/09 37

Protocolo expose con ownership

 : Meeting

 : Person

next.day != freeDay

Valid

Mutable

Committed

inv = 

call reschedule(4)requires this.inv=Valid

owner

next

10/20/09 38

Protocolo expose con ownership

 : Meeting

 : Person

next.day != freeDay

Valid

Mutable

Committed

inv = 

call reschedule(4)

owner

next

10/20/09 39

Protocolo expose con ownership

 : Meeting

 : Person

next.day != freeDay

Valid

Mutable

Committed

inv = 

call reschedule(4)

call re­  sched ule(4)

requires this.inv=Valid

owner

next

10/20/09 40

Protocolo expose con ownership

 : Meeting

 : Person

next.day != freeDay

Valid

Mutable

Committed

inv = 

call reschedule(4)

call re­  sched ule(4)

owner

next

10/20/09 41

Protocolo expose con ownership

 : Meeting

 : Person

next.day != freeDay

Valid

Mutable

Committed

inv = 

call reschedule(4)

call re­  sched ule(4)

owner

next

10/20/09 42

Protocolo expose con ownership

 : Meeting

 : Person

next.day != freeDay

Valid

Mutable

Committed

inv = 

call reschedule(4)

owner

next

10/20/09 43

Protocolo expose con ownership

 : Meeting

 : Person

next.day != freeDay

Valid

Mutable

Committed

inv = 

call reschedule(4)

owner

next

10/20/09 44

Protocolo expose con ownership

 : Meeting

 : Person

next.day != freeDay

Valid

Mutable

Committed

inv = 

En caso de existir,el onwer de Person será el encargado dedevolverlo al estado

Commited

owner

next

10/20/09 45

Invariantes con Ownership

 : Meeting

 : Person

owner

• El ownership debe es una relación acíclica (no puedo poseer a mi dueño)

• Regla de Ownership : Cuando un objeto está Mutable, entonces owner(o), owner(owner(o)), … etc. deben estar en estado Mutable.

• El invariante de un objeto o SÓLO puede depender de :– Los campos de o– Los campos de cualquier objeto que posee 

(transitivamente)

 : Room

owner

owner

null

10/20/09 46

Invariantes usando Ownership

● ¿Qué objetos deben estar Mutables si el objeto Room está Mutable ?

● ¿A los campos de cuáles objetos puede acceder el invariante de Person?

 : Meeting

 : Person

owner

 : Room

owner

owner

null

10/20/09 47

Ownership ­ Implementación

• Por cada objeto existe un nuevo campo ghost: owner– Apunta al “dueño” del objeto

• El modifier rep(resentation) introduce invariantes implícitos de ownership

• inv∈{Committed, Valid, Mutable}

• Un objeto está Committed, si su invariante vale, y  además su owner no está Mutable

10/20/09 48

Referencias Rep ­ Ejemplo

class Person { int freeDay; [rep] Meeting next;

/*implicit invariant next ≠ null ⇒ next.owner = this; */ …}

10/20/09 49

Pack/Unpack con Ownership

unpack o : 

assert o.inv = Valid;o.inv := Mutable;foreach (c  c.owner = o) 

{ c.inv := Valid; }

pack o :

assert o.inv = Mutable;assert ∀c: c.owner = o ⇒ 

c.inv = Valid;foreach (c c.owner = o) 

{ c.inv := Committed; }assert Inv( o );o.inv := Valid

• Extendemos unpack(o) y pack(o) para darle semántica a los invariantes basados en ownership

10/20/09 50

Program Invariant with OwnershipEstado del Heap :

 ∀o: o.inv ≠  mutable ⇒             Inv(o) ∧             (∀c: c.owner = o ⇒ c.inv = Committed))

Invariantes admisibles: ● Contienen sólo accesos a campos de las forma 

● this.f1. … .fn 

● donde f1 … .fn­1  son campos de referencias “rep” 

 

10/20/09 51

Ejemplo (de vuelta)

class Person { int freeDay; rep Meeting next; invariant next ≠ null ⇒

next.day ≠ freeDay; int doTravel(int td) requires inv==valid; modifies this.*; { expose(this) { freeDay = td; if (next!=null) { next.reschedule((td+1)%7); }; }

class Meeting { int day;

void reschedule( int d ) requires inv==valid; { expose(this) {

day = d; }

} }

10/20/09 52

Referencias Rep 

Person person = ... ;

Meeting meeting = ... ;

person.next := meeting ; 

  /*

  como next es una referencia anotada con [Rep],    entonces  asigna a meeting el owner person

   */

10/20/09 53

Referencias Rep

• [Rep] define una jerarquía de objetos• ¿Qué pasa con otros tipos de estructuras ?

10/20/09 54

Ejemplo: Listas cíclicas

Class CyclicList {

  [Rep] Node header;

  /* invariant header.owner == this */

}

Class Node {

   [Rep] Node next;

   /* invariant next.owner == this */

}

10/20/09 55

Ejemplo: Listas cíclicas

Class CyclicList {

  [Rep] Node header;

  /* invariant header.owner == this */

}

Class Node {

   [Rep] Node next;

   /* invariant next.owner == this */

}

:CyclicList

:Node

ownerheader

:Node

next

owner

nextowner?

10/20/09 56

Referencias Peer

Class T1 {

  [rep] Object f1;

  /*f1.owner=this*/  

  …

}

● El modificador [rep] indica que soy el owner de la referencia 

● El modificador [peer], en cambio, indica que la referencia y yo compartimos el mismo owner

10/20/09 57

Referencias Peer

Class T1 {

  [peer] Object f1;

  /*f1.owner=this.owner*/   …

}

● El modificador [rep] indica que soy el owner de la referencia 

● El modificador [peer], en cambio, indica que la referencia y yo compartimos el mismo owner

10/20/09 58

Objetos Peer

class CyclicList { [rep] Node! header; /* implicit invariant     header!=null => header.owner = this;    */}class Node{  [peer] Node! next;  /*implicit invariant     next!=null ⇒ next.owner = this.owner

*/}

10/20/09 59

Verificación modular de invariantes en Spec#

● La metodología soluciona los ● Re­entrada (predicando sobre el campo “inv”) ● Estructuras anidadas (usando ownership)

● Maneja :● Estructuras recursivas (listas)● Recursión mutua (no lo vimos)● Transferencia de ownership (no lo vimos)

10/20/09 60

Verificación modular de invariantes en Spec#

● Posibilita una verificación modular (¿por qué?) ● Verifico usando sólo el invariante de clase bajo 

análisis● Para hablar del estado de los otros objetos, uso el 

protocolo de acceso (campo inv)

● No restringe el aliasing