Date post: | 21-Dec-2015 |
Category: |
Documents |
View: | 218 times |
Download: | 1 times |
Program verification via an intermediate language
K. Rustan M. LeinoMicrosoft Research, Redmond
NUI MaynoothMaynooth, Ireland8 June 2007
CollaboratorsMike BarnettNikolaj BjørnerEvan ChangÁdám DarvasRob DeLineLeo de MouraManuel FähndrichDiego GarbervetskyBart JacobsFrancesco Logozzo
Rosemary MonahanMichaŀ MoskalPeter MüllerMadan MusuvathiDave NaumannSimon OuArnd Poetzsch-HeffterWolfram SchulteHerman VenterAngela Wallenburg…
Grand Challenge of
Verified SoftwareHoare, Joshi, Leavens, Misra, Naumann, Shankar, Woodcock, et al.
“We envision a world in which computer programs are always the most reliable component of any system or device that contains them” [Hoare & Misra]
Spec# programming systemSpec# language
Object-oriented .NET languageMore typesSpecifications (pre- and postconditions, etc.)
Usage rules (methodology)Checking:
Static type checkingRun-time checkingStatic verification (optional)
Static verificationsound modular verificationfocus on automation, not full functional correctness specificationsno termination verificationno verification of temporal properties
stati
c veri
fier
(Boog
ie)
MSIL (“bytecode”)
SMT solver
V.C. generator
Inference engine
translator
verification condition
“correct” or list of errors
Spec# compiler
Spec#
BoogiePL
Spec# verifier architecture
BoogiePLC Eiffel …Java+JMLSpec#
Simplify
Z3 CVC 3SMT Lib
Coq …
BoogiePL
abstract interpreterpredicate
abstractiontermination detector
…
While and gotoThe code:
x := 0;while (x < 0)
invariant 0 ≤ x && x ≤ 10;{
x := x + 1;}
is equivalent to:x := 0; goto Head;Head: assert 0 ≤ x && x ≤ 10; goto Body, Done;Body: assume x < 10; x := x + 1; goto Head;Done: assume 10 ≤ x;
Procedure callsGiven:
procedure M();requires P; modifies w; ensures Q;
the code:call M();
is equivalent to:assert P; havoc w; assume Q;
(ignoring old expressions, and not showing parameters)
Example: source programclass C : object {
int x;C() { … } virtual int M(int n) { … } static void Main() {
C c = new C();c.x = 12;int y = c.M(5);
}}
Example: BoogiePL translation (0)// class typesconst unique System.Object: name;const unique C: name;
axiom C <: System.Object;
function typeof(o: ref) returns (t: name);
// fieldstype field;const unique C.x: field;const unique allocated: field;
// the heapvar Heap: [ref, field] int;
class C: object {
int x;
Example: BoogiePL translation (1)// method declarations
procedure C..ctor(this: ref); requires this != null && typeof(this) <: C; modifies Heap;
procedure C.M(this: ref, n: int) returns (result: int); requires this != null && typeof(this) <: C; modifies Heap;
procedure C.Main(); modifies Heap;
C() { … }
virtual int M(int n)
static void Main()
Example: BoogiePL translation (2)// method implementationsimplementation C.Main(){ var c: ref, y: int;
havoc c; assume c != null; assume Heap[c, allocated] ==
0; assume typeof(c) == C; Heap[c, allocated] := 1; call C..ctor(c);
assert c != null; Heap[c, C.x] := 12;
call y := C.M(c, 5);
}
C c = new C();
c.x = 12;
int y = c.M(5);
Modeling the heapclass C { int f; object g; }var f: [ref] int;var g: [ref] ref;type Field; type Value;var Heap: [ref, Field] Value;function V2I(Value) returns (int);function I2V (int) returns (Value);axiom ( v: Value I2V(V2I(v)) == v);axiom ( i: int V2I(I2V(i)) == i);type Field ;var Heap: ( [ref, Field ] );
x = c.f;
x := f [ c ];x = c.f;
x := V2I(Heap[ c, f ]);
x = c.f;
x := Heap[ c, f ];
Example:Chunker.NextChunk specificationpublic string NextChunk() modifies this.*; ensures result.Length <=
ChunkSize;
Chunker.NextChunk translationprocedure Chunker.NextChunk(this: ref where $IsNotNull(this, Chunker)) returns ($result: ref where $IsNotNull($result, System.String)); // in-parameter: target object free requires $Heap[this, $allocated]; requires ($Heap[this, $ownerFrame] == $PeerGroupPlaceholder || !($Heap[$Heap[this, $ownerRef], $inv] <: $Heap[this, $ownerFrame]) ||
$Heap[$Heap[this, $ownerRef], $localinv] == $BaseClass($Heap[this, $ownerFrame])) && (forall $pc: ref :: $pc != null && $Heap[$pc, $allocated] && $Heap[$pc, $ownerRef] == $Heap[this, $ownerRef] && $Heap[$pc, $ownerFrame] == $Heap[this, $ownerFrame] ==> $Heap[$pc, $inv] == $typeof($pc) && $Heap[$pc, $localinv] == $typeof($pc));
// out-parameter: return value free ensures $Heap[$result, $allocated]; ensures ($Heap[$result, $ownerFrame] == $PeerGroupPlaceholder || !($Heap[$Heap[$result, $ownerRef], $inv] <: $Heap[$result, $ownerFrame]) ||
$Heap[$Heap[$result, $ownerRef], $localinv] == $BaseClass($Heap[$result, $ownerFrame])) && (forall $pc: ref :: $pc != null && $Heap[$pc, $allocated] && $Heap[$pc, $ownerRef] == $Heap[$result, $ownerRef] && $Heap[$pc, $ownerFrame] == $Heap[$result, $ownerFrame] ==> $Heap[$pc, $inv] == $typeof($pc) && $Heap[$pc, $localinv] == $typeof($pc));
// user-declared postconditions ensures $StringLength($result) <= $Heap[this, Chunker.ChunkSize]; // frame condition modifies $Heap; free ensures (forall $o: ref, $f: name :: { $Heap[$o, $f] } $f != $inv && $f != $localinv && $f != $FirstConsistentOwner && (!IsStaticField($f) || !
IsDirectlyModifiableField($f)) && $o != null && old($Heap)[$o, $allocated] && (old($Heap)[$o, $ownerFrame] == $PeerGroupPlaceholder || !(old($Heap)[old($Heap)[$o, $ownerRef], $inv] <: old($Heap)[$o, $ownerFrame]) || old($Heap)[old($Heap)[$o, $ownerRef], $localinv] == $BaseClass(old($Heap)[$o, $ownerFrame])) && old($o != this || !(Chunker <: DeclType($f)) || !$IncludedInModifiesStar($f)) && old($o != this || $f != $exposeVersion) ==> old($Heap)[$o, $f] == $Heap[$o, $f]);
// boilerplate free requires $BeingConstructed == null; free ensures (forall $o: ref :: { $Heap[$o, $localinv] } { $Heap[$o, $inv] } $o != null && !old($Heap)[$o, $allocated] && $Heap[$o, $allocated] ==>
$Heap[$o, $inv] == $typeof($o) && $Heap[$o, $localinv] == $typeof($o)); free ensures (forall $o: ref :: { $Heap[$o, $FirstConsistentOwner] } old($Heap)[old($Heap)[$o, $FirstConsistentOwner], $exposeVersion] ==
$Heap[old($Heap)[$o, $FirstConsistentOwner], $exposeVersion] ==> old($Heap)[$o, $FirstConsistentOwner] == $Heap[$o, $FirstConsistentOwner]);
free ensures (forall $o: ref :: { $Heap[$o, $localinv] } { $Heap[$o, $inv] } old($Heap)[$o, $allocated] ==> old($Heap)[$o, $inv] == $Heap[$o, $inv] && old($Heap)[$o, $localinv] == $Heap[$o, $localinv]);
free ensures (forall $o: ref :: { $Heap[$o, $allocated] } old($Heap)[$o, $allocated] ==> $Heap[$o, $allocated]) && (forall $ot: ref :: { $Heap[$ot, $ownerFrame] } { $Heap[$ot, $ownerRef] } old($Heap)[$ot, $allocated] && old($Heap)[$ot, $ownerFrame] != $PeerGroupPlaceholder ==> old($Heap)[$ot, $ownerRef] == $Heap[$ot, $ownerRef] && old($Heap)[$ot, $ownerFrame] == $Heap[$ot, $ownerFrame]) && old($Heap)[$BeingConstructed, $NonNullFieldsAreInitialized] == $Heap[$BeingConstructed, $NonNullFieldsAreInitialized];
QuantifiersInstantiation via e-graph matchingA matching pattern (trigger) is a set of terms that together mention all the bound variables, and none of which is just a bound variable by itselfExamples:
(x { f(x) } 0 ≤ f(x))(x,y { g(x,y) } f(x) < g(x,y))
More trigger examples(x,y { f(x), f(y) } x ≤ y f(x) ≤ f(y))(x { f(x) } x ≠ null f(x) ≤ f(next(x)))(x { f(next(x)) } x ≠ null f(x) ≤ f(next(x)))(x,y { f(x), f(y) } f(x) = f(y) x = y)(x { f(x) } fInv(f(x)) = x)(x { f(x+1) } f(x) ≤ f(x+1))(x,y,z { x*(y+z) } x*(y+z) = x*y + x*z)(x,y { P(x,y) } x = y P(x,y) = 10)(x { P(x,x) } P(x,x) = 10)
Download
Spec# and
Boogie
from here
ConclusionsSpec# is an object-oriented language with
specificationsBoogiePL is an intermediate verification language
Separates concernsEnables sharing in the verification community
front ends for multiple languagesbenchmarksabstract interpretationVC generationmultiple theorem proverspredicate abstraction…
http://research.microsoft.com/specsharp