invariantes - dc.uba.ar · se verifica que vale a la salida del método – ... /*@ nullable @*/...
TRANSCRIPT
¿Qué es un invariante?
● Un invariante es un predicado que especifica qué estados de un objeto son consistentes.
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 preestado y el postestado 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.)
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; }
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 … .fn1 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 ● Reentrada (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)