Parte 1

Anuncio
Verificación de Programas
Orientados a Objetos
j
Análisis Automático de Código (2008)
Spec#
Francisco Bavera – Germán Regis
24/11/08
Presentación parcialmente basada en el tutorial de ETAPS 2008 de Leino y Monaham.
Un Problema de Ingeniería de
S ft
Software
Problema
Desarrollar y mantener programas correctos.
Un enfoque
Especificaciones
p
registra
g
decisiones de diseño.
Herramientas amplifican el esfuerzo del
programador
Manejan detalles
Encuentran inconsistencias
Aseguran
g
calidad
2
Spec#
El Sistema de Programación Spec# provee un lenguaje y
herramientas para verificar aserciones en programas
orientados a objetos.
El lenguaje de programación Spec#: extensión de C#
con tipos non-null, contratos e invariantes de objetos.
El compilador Spec#: compilador que verifica
estáticamente tipos non-null y genera verificaciones en
tiempo de ejecución para contratos e invariantes
ifi d estático
táti Spec#:
S
# este
t componente
t
El verificador
(Boogie) genera condiciones de verificación de
programas Spec#. Internamente, usa un theorem
prover automático
t áti que analiza
li lla condición
di ió d
de
verificación para probar la correción del programa o
encontrar errores.
3
Spec#
El lenguaje Spec#:
Lenguaje. NET
Extensión de C#,
Incluye: más tipos
Especificaciones (pre
(pre- y postcondiciones,
postcondiciones etc
etc.))
Verificación:
Chequeos estáticos de tipos
q
p de ejecución
j
Chequeos
en tiempo
Verificación estática de programas
4
Instalando Spec#
Bajar e instalar Spec# de
http://research microsoft com/specsharp/
http://research.microsoft.com/specsharp/
Instalación incluye: el compilador, VS plug-in,
Boogie, Z3
Requiere: .NET
Recomendado: Visual Studio
Opcional: Simplify
5
Como usamos Spec#
El programador escribe cada clase con su
especificación en un archivo fuente Spec#
(similar a Eiffel o Java+JML)
Entonces se puede ejecutar el verificador.
El verificador
ifi d se puede
d iinvocar como ell
compilador (de el IDE de Visual Basic o de la
línea de comandos
La interacción con el verificador se realiza
modificando el archivo fuente.
6
El Lenguaje Spec#
Spec#
p
es una extensión de C#, un lenguaje
g j
orientado a objetos para la plataforma
f
.NET
C# incluye
i l
herencia
h
i simple
i l (clases
( l
pueden
d
implementar múltiples interfaces), referencias a
objetos,
invocación dinámica de métodos y
j
excepciones.
Spec# incluye tipos non-null,
non null contratos e
invariantes.
7
Non--Null
Tipos Non
En C#, cada tipo T que es una referencia
incluye el valor null
Referencia a null (null dereference) es un error
común en los programas.
En Spec#, el tipo T! contiene solo referencias a
null)
objetos de tipo T (no contiene el valor null).
int []! xs;
declara un arreglo xs que no puede ser null.
8
Ejemplo de Tipo Non
Non--Null
public
bli class
l
P
Program
{
public static void Main(string[] args)
{
foreach (string arg in args) // Posible referencia null
{
Console.WriteLine(arg); // Posible referencia null
}
Console.ReadLine();
}
}
9
Non--Null
Tipos Non
Spec# permite asignar la responsabilidad de
asegurar que el parámetro sea non-null al
i
d d
ét d
invocador
dell método.
Spec# retorna Error: null is not a valid
argument en caso de que un valor null se pase
a un método q
que requiera
un p
parámetro nonq
null.
10
Ejemplo de Tipo Non
Non--Null
public
bli class
l
P
Program
{
public static void Main(string![] ! args)
{
foreach (string arg in args)
{
Console.WriteLine(arg);
args != null
}
args[i] != null
Console.ReadLine();
}
}
11
Inicializando Atributos Non
Non--Null
class C : B {
T ! x;
public C(T ! y) {
base();
this.x = y;
this P();
this.P();
}
Es type safe?
No!
abstract class B {
public B() { this.M(); }
public abstract int M();
}
public override int M()
p
() { return x.f;; }
}
Referencia a null
12
Inicializando Atributos Non
Non--Null
class C : B {
T ! x;
Spec# permite que x
S asignado
Sea
i
d antes
t d
de
invocar el constructor base.
public C(T ! y) {
this.x = y;
base();
this P();
this.P();
}
public override int M()
p
() { return x.f;; }
}
13
Inicializando Atributos Non
Non--Null
using
i
Mi
Microsoft.Contracts;
ft C t t
class C {
T! x;
[NotDelayed]
public
bli C(int
C(i t k) {
x = new T(k);
b
base();
()
x.M();
}
Permite que los
atributos
sean leidos
Spec# permite
llamadas base()
en cualquier lugar
En constructores
E
t t
non-delayed,
d l
d ttodos
d llos atributos
t ib t
non-null se deben inicializar antes de invocar base()
14
Assert
public void [DoSomething(Node] node) {
assert node != null; // verificado en run-time
// normal processing continues
}
15
Assert en C#
public void [DoSomething(Node] node) {
if ( node == null ) {
throw [ApplicationException(...);]
}
else {
// normal processing continues
}
}
System.Diagnostics.Debug.Assert
public void [DoSomething(Node] node) {
System.Diagnostics.Debug.Assert(node !!= null);
// normal processing continues
}
16
Assume
assume E es como assert E, en tiempo
de ejecución,
ejecución pero el verificador estático
verifica el assert mientras que asume el
assume.
17
Especificaciones de Métodos
y
Una especificación tiene tres partes:
requires P;
modifies x;
ensures Q;
y
// precondición
// frame condition
// postcondición
Una especificación es un contrato entre el
invocador y la implementación:
◦ Invocador debe establecer P antes de invocar
x Implementación puede asumir P en la entrada del
método.
◦ Implementación debe establecer Q antes de
retornar, y solo debe modificar x
x Invocador puede asumir Q cuando retorna u que solo
18
fue modificado x.
Especificaciones en .NET
S i B ild A
StringBuilder.Append
dM
Method
h d (Ch
(Char[[ ],
] Int32,
I 32 Int32)
I 32)
Appends the string representation of a specified subarray of Unicode characters to the end of this
instance.
public StringBuilder Append(char[] value, int startIndex, int charCount);
Parameters
value
A character array.
startIndex
The starting position in value.
charCount
The number of characters append.
Return Value
A reference to this instance after the append operation has occurred.
Exceptions
Exception Type
Condition
ArgumentNullException
value is a null reference, and startIndex and charCount are not zero.
ArgumentOutOfRangeException
charCount is less than zero.
-orstartIndex is less than zero.
-orstartIndex + charCount is less than the length of value.
19
Precondiciones
public StringBuilder Append(char[] value, int startIndex,
int charCount );
requires value == null
==> startIndex == 0 && charCount == 0;
requires 0 <= startIndex;
requires 0 <= charCount;
requires value == null || startIndex + charCount <= value.Length;
Exception Type
Condition
ArgumentNullException
value is a null reference, and startIndex and charCount are not zero.
ArgumentOutOfRangeException
charCount is less than zero.
-orstartIndex is less than zero.
-orstartIndex + charCount is less than the length of value.
20
Claúsulas Otherwise
public StringBuilder Append( char[ ] value, int startIndex,
int charCount );
requires
q
value != null ll startIndex == 0 && charCount == 0
otherwise ArgumentNullException;
requires
q
0 <= startIndex
otherwise ArgumentOutOfRangeException;
…
Exception Type
Condition
ArgumentNullException
g
value is a null reference, and startIndex and charCount are not zero.
ArgumentOutOfRangeException
charCount is less than zero.
-orstartIndex is less than zero
zero.
-orstartIndex + charCount is less than the length of value.
21
Claúsulas Throw
void ReadToken (ArrayList a)
throws EndOfFileException ensures a.Count ==old(a.Count);
22
Claúsula Modifies
static void Swap(int[] a
a, int i,
i int j)
requires 0 <= i && i < a.Length;
requires
q
0 <= j && j < a.Length;
g
modifies a[i], a[j];
ensures a[i] == old(a[j]);
ensures a[j] == old(a[i]);
{
int temp;
frame conditions limita que partes
temp = a[i];
del estado del pprograma
g
ppueden ser
a[i] = a[j];
j
modificadas por el programa.
a[j] = temp;
}
23
Herencia y Contratos
interface J {
void M(int x); requires P;
}
class A {
public abstract void M(int x); requires Q;
}
class B : A,
A J{
public override void M(int x)
{…}
}
Ciclos en Spec#
p
public static int SegSum(int[]! a, i int i, int j)
requires 0 <= i && i <= j && j <= a.Length;
ensures result == sum{int k in (i: j); a[k]};
{
int s = 0;;
for (int n = i; n < j; n++)
{
s += a[n];
}
return s;
}
25
Ciclos en Spec#
p
public static int SegSum(int[]! a, i int i, int j)
requires 0 <= i && i <= j && j <= a.Length;
ensures result == sum{int k in (i: j); a[k]};
{
int s = 0;;
for (int n = i; n < j; n++)
{
Cuando se trata de verificar
s += a[n];
usando Spec#, se genera el
}
siguiente error: Array index
return s;
possibly below lower bound;
el verificador necesitas más
}
información.
26
Invariantes de Ciclos
public static int SegSum(int[]! a, int i, int j)
requires
i
0 <= i && i <= j && j <= a.Length;
h
ensures result == sum{int k in (i: j); a[k]};
{ int
i t s = 0;
0
for (int n = i; n < j; n++)
invariant i <= n && n <= j;
invariant s == sum{int k in (i: n); a[k]};
{
s += a[n];
}
return s;
}
27
Invariantes de Ciclos
public static int SegSum(int[]! a, int i, int j)
requires
i
0 <=ii && i <= j && j <= a.Length;
h
ensures result == sum{int k in (i:j); a[k]};
{ int
i t s = 0;
0
for (int n = i; n < j; n++)
invariant i <= n && n <= j;
invariant s == sum{int k in (i:n); a[k]};
{
s += a[n];
Verifier Output:
}
Spec# Program Verifier
return s;
finished with 3 verified,
}
0 errors
28
Funciones Variantes
public static int SegSum(int[]! a, int i, int j)
requires
i
0 <= i && i <= j && j <= a.Length;
h
ensures result == sum{int k in (i: j); a[k]};
{ int
i t s = 0;
0 int
i t n=i;
i
while (n < j)
invariant i <= n && n <= j;
invariant s == sum{int k in (i: n); a[k]};
invariant 0<
0<= j - n;
{ int vf = j - n; // función variante
s +=
+ a[n]; n++;
assert j - n < vf;
}
return s;
}
Se puede
S
d usar assert
para determinar
información acerca de la
función variante.
29
Arquitectura
q
del Verificador Spec#
p
Spec#
Compilador Spec#
MSIL (“bytecode”)
( bytecode )
verificador estático (Boogie)
Traductor
Motor Inferencia
BoogiePL
Generador VC
C di ió verificación
Condición
ifi
ió
Probador teoremas
correcto o lista de errores
30
BoogiePL
Spec#
C
Java+JML
Eiffel
…
Interprete abstracto
Abstracción predicados
BoogiePL
Detector terminación
…
Simplify
Z3
CVC 3
SMT Lib
Coq
…
31
BoogiePL
y
L
Lenguaje
j IIntermedio
di
y
La semántica de Spec# es codificada en
g
BoogiePL
y
Puede ser usado pra otras actividades de
verificación (como verificar otros lenguajes
fuentes).
fuentes)
32
Ejemplo: Traducción Spec# a BoogiePL
class C : object {
int x;
C() { … }
virtual int M(int n) { … }
static void Main() {
C c = new C();
c x = 12;
c.x
int y = c.M(5);
}
}
33
Ejemplo: Traducción Spec# a BoogiePL
// class types
const unique
q
System.Object: name;
y
j
;
const unique C: name;
class
l
C
: object {
axiom C <: System.Object;
C <: System Object;
function typeof(o: ref) returns (t: name);
// fields
type
yp field;
;
const unique C.x: <int>field;
const unique allocated: <bool>field;
int x;
// the heap
var Heap: [ref, <α>field]α;
34
Ejemplo: Traducción Spec# a BoogiePL
Spec#
if (Guard) S else T
BoogiePL
Then
Branch
assume Guard;
S
assume !Guard;
T
Else
Branch
35
Ejemplo: Traducción Spec# a BoogiePL
Spec#
while (Guard(x))
(G
( )) invariant Inv(x)
( ) { S(x)
S( ) }
BoogiePL
Loop Pre- assert Inv(x)
( )
d
decessor
Loop Head
havoc x;
assume Inv(x);
Loop
assume !Guard(x);
Exit
assume Guard(x);
S(x)
Loop Body
assert Inv(x)
36
Condiciones de Verificación
y
Usa un lenguaje intermedio: BoogiePL
y
Probador de Teoremas Automático (Z3)
( )
◦ Puede ocultarse al programador
◦ Genera contra-ejemplos
y
Probador de Teoremas Interactivo
◦ Requiere
q
“gurus”
g
37
Chunker NextChunck
Chunker.NextChunck
public string! NextChunk()
modifies this.*;
g <= ChunkSize;
ensures result.Length
{
string s;
if (n + ChunkSize <= src.Length) {
s = src.Substring(n, ChunkSize);
} else {
s = src.Substring(n);
}
n += s.Length;
return s;
}
38
Chunker.ChunkSize))) (IMPLIES (< 0 (select2 $Heap@5 this Chunker.ChunkSize)) (AND (LBLNEG |@28274| (<= 0 (select2 $Heap@5 this
Chunker.n))) (IMPLIES (<= 0 (select2 $Heap@5 this Chunker.n)) (AND (LBLNEG |@28285| (<= (select2 $Heap@5 this Chunker.n) ($StringLen
(select2 $Heap@5 this Chunker.src)))) (IMPLIES (<= (select2 $Heap@5 this Chunker.n) ($StringLength (select2 $Heap@5 this Chunker.src)))
(LBLNEG |@28303| (FORALL ($p) (QID unknown.0:0) (SKOLEMID 55) (IMPLIES (AND (AND (NEQ $p nullObject) (EQ (select2 $Heap@5 $p
$allocated) |@true|)) (AND (EQ (select2 $Heap@5 $p $ownerRef) this) (EQ (select2 $Heap@5 $p $ownerFrame) Chunker))) (AND (EQ (select
$Heap@5 $p $inv) ($typeof $p)) (EQ (select2 $Heap@5 $p $localinv) ($typeof $p)))))) (IMPLIES (FORALL ($p) (QID unknown
unknown.0:0)
0:0) (SKOLEMID
(IMPLIES (AND (AND (NEQ $p nullObject) (EQ (select2 $Heap@5 $p $allocated) |@true|)) (AND (EQ (select2 $Heap@5 $p $ownerRef) this) (
(select2 $Heap@5 $p $ownerFrame) Chunker))) (AND (EQ (select2 $Heap@5 $p $inv) ($typeof $p)) (EQ (select2 $Heap@5 $p $localinv) ($typ
$p))))) (IMPLIES (EQ $Heap@6 (store2 $Heap@5 this $localinv ($typeof this))) (IMPLIES (EQ (IsHeap $Heap@6) |@true|) (IMPLIES TRUE
block4607-2-block4590_correct)))))))))))))))))))) (FORMULA true4471to4607_correct (IMPLIES (LBLPOS |+5569| TRUE) (IMPLIES TRUE (IMPL
(EQ nullObject nullObject) (IMPLIES TRUE block4607_correct))))) (FORMULA true4505to4607_correct (IMPLIES (LBLPOS |+5733| TRUE)
(IMPLIES TRUE (IMPLIES (NEQ ($A
($As nullObject
llObj t Mi
Microsoft.Contracts.ICheckedException)
ft C t t ICh k dE
ti ) nullObject)
llObj t) (IMPLIES TRUE bl
block4607_correct)))))
k4607
t)))))
(FORMULA block4556-2-block4590_correct (IMPLIES (LBLPOS |+25363| TRUE) (IMPLIES (EQ $Heap@7 $Heap@5) (IMPLIES (EQ stack0s@
stack0s) (IMPLIES (EQ stack0o@4 nullObject) block4590_correct))))) (FORMULA block4556_correct (IMPLIES (LBLPOS |+5737| TRUE) (IMPL
TRUE (IMPLIES TRUE block4556-2-block4590_correct)))) (FORMULA false4505to4556_correct (IMPLIES (LBLPOS |+5735| TRUE) (IMPLIES
TRUE (IMPLIES (EQ ($As nullObject Microsoft.Contracts.ICheckedException) nullObject) (IMPLIES TRUE block4556_correct))))) (FORMULA
block4505_correct
_
((IMPLIES ((LBLPOS ||+5575|| TRUE)) (IMPLIES
(
TRUE (IMPLIES
(
TRUE (AND
(
true4505to4607_correct
_
false4505to4556_correct))))) (FORMULA false4471to4505_correct (IMPLIES (LBLPOS |+5571| TRUE) (IMPLIES TRUE (IMPLIES (NEQ nullOb
nullObject) (IMPLIES TRUE block4505_correct))))) (FORMULA block4471_correct (IMPLIES (LBLPOS |+5554| TRUE) (IMPLIES TRUE (IMPLIE
TRUE (AND true4471to4607_correct false4471to4505_correct))))) (FORMULA block4284_correct (IMPLIES (LBLPOS |+5401| TRUE) (IMPLIES
TRUE (AND (LBLNEG |@27875| (NEQ this nullObject)) (IMPLIES (NEQ this nullObject) (IMPLIES (EQ stack0i@2 (select2 $Heap@4 this
Chunker.n)) (AND (LBLNEG |@27893| (NEQ s@0 nullObject)) (IMPLIES (NEQ s@0 nullObject) (IMPLIES (EQ stack1i@5 ($StringLength s@0)
(IMPLIES (EQ stack0i@3 (+ stack0i@2 stack1i@5)) (AND (LBLNEG |@27916| (NEQ this nullObject)) (IMPLIES (NEQ this nullObject) (AND
(LBLNEG |@27923| (OR (EQ (select2 $Heap@4 this $ownerFrame) $PeerGroupPlaceholder) (OR (NOT (EQ (<: (select2 $Heap@4 (select2
$Heap@4 this $ownerRef) $inv) (select2 $Heap@4 this $ownerFrame)) |@true|)) (EQ (select2 $Heap@4 (select2 $Heap@4 this $ownerRef)
$localinv) ($BaseClass (select2 $Heap@4 this $ownerFrame)))))) (IMPLIES (OR (EQ (select2 $Heap@4 this $ownerFrame)
$PeerGroupPlaceholder) (OR (NOT (EQ (<: (select2 $Heap@4 (select2 $Heap@4 this $ownerRef) $inv) (select2 $Heap@4 this $ownerFrame)
|@true|)) (EQ (select2 $Heap@4 (select2 $Heap@4 this $ownerRef) $localinv) ($BaseClass (select2 $Heap@4 this $ownerFrame))))) (IMPLIES
( Q $Heap@5
(EQ
$
@ (store2
(
$
$Heap@4
@ this Chunker.n
C
stack0i@3))
@ )) ((AND ((LBLNEG
G |@28007|
|@
| (OR
(O (NOT
( O (AND
(
(EQ
( Q (<:
( (select2
(
$
$Heap@5
@ this $inv)
$ )
Chunker) |@true|) (NEQ (select2 $Heap@5 this $localinv) ($BaseClass Chunker)))) (< 0 (select2 $Heap@5 this Chunker.ChunkSize)))) (IMPLIE
(OR (NOT (AND (EQ (<: (select2 $Heap@5 this $inv) Chunker) |@true|) (NEQ (select2 $Heap@5 this $localinv) ($BaseClass Chunker)))) (< 0
(select2 $Heap@5 this Chunker.ChunkSize))) (AND (LBLNEG |@28055| (OR (NOT (AND (EQ (<: (select2 $Heap@5 this $inv) Chunker) |@true
(NEQ (select2 $Heap@5 this $localinv) ($BaseClass Chunker)))) (<= 0 (select2 $Heap@5 this Chunker.n)))) (IMPLIES (OR (NOT (AND (EQ (<
((select2 $
$Heap@5
p@ this $
$inv)) Chunker)) |@
|@true|)
|) (NEQ
( Q (select2
(
$Heap@5
$
p@ this $
$localinv)) ($
($BaseClass Chunker))))
)))) ((<= 0 ((select2 $
$Heap@5
p@ this
Chunker.n))) (AND (LBLNEG |@28103| (OR (NOT (AND (EQ (<: (select2 $Heap@5 this $inv) Chunker) |@true|) (NEQ (select2 $Heap@5 this
$localinv) ($BaseClass Chunker)))) (<= (select2 $Heap@5 this Chunker.n) ($StringLength (select2 $Heap@5 this Chunker.src))))) (IMPLIES (O
(NOT (AND $Heap@5 this Chunker.n) ($StringLength (select2 $Heap@5 this Chunker.src)))) (IMPLIES (EQ (IsHeap $Heap@5) |@true|) (IMPL
TRUE block4471_correct))))))))))))))))))))))) (FORMULA block4267-2-block4284_correct (IMPLIES (LBLPOS |+25361| TRUE) (IMPLIES (EQ
stack2i@1 stack2i) (IMPLIES (EQ s@0 call4133formal@$result@0) (IMPLIES (EQ stack1i@4 stack1i@3) (IMPLIES (EQ $ActivityIndicator@2
$ActivityIndicator@1) (IMPLIES (EQ stack0o@2 stack0o@1) (IMPLIES (EQ $Heap@4 $Heap@3) block4284
block4284_correct))))))))
correct)))))))) (FORMULA
block4267_correct (IMPLIES (LBLPOS |+2908| TRUE) (IMPLIES TRUE (AND (LBLNEG |@26919| (NEQ this nullObject)) (IMPLIES (NEQ this
nullObject) (IMPLIES (EQ stack0o@1 (select2 $Heap@1 this Chunker.src)) (AND (LBLNEG |@26937| (NEQ this nullObject)) (IMPLIES (NEQ th
nullObject) (IMPLIES (EQ stack1i@3 (select2 $Heap@1 this Chunker.n)) (AND (LBLNEG |@26955| (NEQ stack0o@1 nullObject)) (IMPLIES (N
stack0o@1 nullObject) (IMPLIES (AND (EQ ($IsNotNull call4133formal@$result System.String) |@true|) (EQ (select2 $Heap
call4133formal@$result $allocated) |@true|)) (AND (LBLNEG |@26962| (<= 0 stack1i@3)) (IMPLIES (<= 0 stack1i@3) (AND (LBLNEG |@2696
Condiciones de Verificación:
Chunker.NextChunck
Otra Herramienta
y
y
y
y
y
ESC/Java
E f
Enfoque
similar
i il a SSpec#
#
Usa el mismo probador Simplify
Usa el lenguaje de especificación JML
Actualmente no cuenta con un GUI estable?
40
Resumiendo
y
Spec#
yExtiende C# con contratos.
contratos
yPuede ser usado para verificación estática y
dinámica.
yNo es completo.
completo
yEficiente y Práctico.
yEn desarrollo.
yExiste herramientas similares (ESC/Java)
41
Referencias y Recursos
y
y
y
Spec# website
http://research.microsoft.com/specsharp/
The Spec# programming system: An
overview. Mike Barnett, K. Rustan M. Leino,
and Wolfram Schulte. In CASSIS 2004,, LNCS vol.
3362, Springer, 2004.
Boogie:
g A Modular Reusable Verifier for Objectj
Oriented Programs. Mike Barnett, Bor-Yuh Evan
Chang, Robert DeLine, Bart Jacobs, and K.
Rustan M. Leino. In FMCO 2005, LNCS vol.
4111, Springer, 2006.
42
Descargar