260 likes | 453 Views
Spec#. K. Rustan M. Leino Principal Researcher Microsoft Research, Redmond, WA, USA. 14 Nov 2007 Øredev Malm ö, Sweden. Collaborators. Mike Barnett Nikolaj Bjørner Ádám Darvas Leonardo de Moura Manuel F ä hndrich Bart Jacobs Francesco Logozzo. Ronald Middelkoop Peter Müller
E N D
Spec# K. Rustan M. Leino Principal ResearcherMicrosoft Research, Redmond, WA, USA 14 Nov 2007ØredevMalmö, Sweden
Collaborators • Mike Barnett • Nikolaj Bjørner • Ádám Darvas • Leonardo de Moura • Manuel Fähndrich • Bart Jacobs • Francesco Logozzo • Ronald Middelkoop • Peter Müller • Ralf Sasse • Wolfram Schulte • Herman Venter • Angela Wallenburg
Microsoft Research • Take risks • Advance state of the art, state of knowledge • Over time, have a significant impact on Microsoft products • First “customers”: early adopters
Want feedback What seems useful to you? Email me, leino@microsoft.com or—better yet—the Spec# mailing list, see http://research.microsoft.com/specsharp
Software engineering problem • Problem • Building and maintaining programs that are correct • Approach • Specifications record design decisions • bridge intent and code • Tools amplify human effort • manage details • find inconsistencies • ensure quality
Research goals • Build the best such system we can build today • Experiment with the system to get a feel for what it is like to use • Advance the state of the art
Spec# programming system • Spec# language • Object-oriented .NET language • Superset of C#, adding: • more types • specifications (pre- and postconditions, etc.) • Usage rules (methodology) • Checking: • Static type checking • Run-time checking • Static program verification (optional)
Program specifications– the academic view { P }S{ Q } If program S is started in a state satisfying the precondition P, then • the execution of S will not go wrong and • if the execution terminates, it does so in a state satisfying the postcondition Q If S starts in P, then it ends in Q
Specifications: .NET today StringBuilder.Append Method (Char[], Int32, Int32) Appends the string representation of a specified subarray of Unicode characters to the end of this instance. publicStringBuilderAppend(char[] value, intstartIndex, intcharCount); 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
Specifications in Spec# publicStringBuilderAppend(char[] value, intstartIndex,intcharCount ); requires value == null ==> startIndex == 0 && charCount == 0; requires0 <= startIndex; requires 0 <= charCount; requires value == null ||startIndex + charCount <= value.Length;
Method specifications • A specification has three parts: requires P; // preconditionmodifies x; // frame conditionensures Q; // postcondition • A specification is a contract between callers and implementions: • Caller must establish P before call • Implementation can assume P on entry to method • Implementation must establish Q before returning, and must only modify x • Caller can assume Q holds upon return,and that only x was modified
Multi-object invariants :Chunker :Chunker :Classroom n: 84 n: 20 invstudentGrades.Count ≤ 20; invdict.Count ≤ n; invdict.Count ≤ n; rep dict: dict: studentGrades: owner :Dictionary Count: 21
C# compatibility • Spec# is superset of C# • From C# to Spec#: • accept every C# program • compile it to have the same behavior • Consequences • “Possible null dereference” is just a warning • “Must initialize non-null fields before calling base constructor” is an error • Support for out-of-band contracts
From Spec# to C#or: Leveraging wiz-bang features of Visual Studio 2005 class B : A {string! src;public B(string! source, intx)requires0 <= x; {this.src = source;base(x); }
From Spec# to C#or: Leveraging wiz-bang features of Visual Studio 2005 class B : A {stringsrc;publicB(stringsource, intx) //^ requires 0 <= x; : base(x) {this.src = source;//^ base; }
C# mode • Show and tell
Backward compatibility requires 0 <= startIndex otherwiseArgumentOutOfRangeException;
Exceptions • Program errors • e.g., NullPointerException, ArrayBoundsException • Parameter validation • e.g., ArgumentException • Unanticipated events • e.g., OutOfMemoryError, InternalCLRError • Anticipated conditions • e.g., SocketClosedException type checking,program verification preconditions throws clauses
Exceptions • Show and tell
Inheriting contracts • interface J {void M(int x); requires P;} • class A {publicabstractvoid M(int x); requires Q;} • class B : A, J {publicoverridevoid M(int x) { … }}
Spec# verifier architecture Spec# Spec# compiler MSIL (“bytecode”) Translator BoogiePL Inference engine static verifier (Boogie) V.C. generator verification condition SMT solver “correct” or list of errors
Chunker.NextChunk publicstring! NextChunk() modifiesthis.*; ensuresresult.Length <= ChunkSize; { string s; if (n + ChunkSize <= src.Length) { s = src.Substring(n, ChunkSize); } else { s = src.Substring(n); } n += s.Length; return s; }
(LET ((FORMULA ReallyLastGeneratedExit_correct (IMPLIES (LBLPOS |+25122| TRUE) (AND (LBLNEG |@28448| (OR (EQ (select2 $Heap@7 s@0 $ownerFrame) $PeerGroupPlaceholder) (OR (NOT (EQ (<: (select2 $Heap@7 (select2 $Heap@7 s@0 $ownerRef) $inv) (select2 $Heap@7 s@0 $ownerFrame)) |@true|)) (EQ (select2 $Heap@7 (select2 $Heap@7 s@0 $ownerRef) $localinv) ($BaseClass (select2 $Heap@7 s@0 $ownerFrame)))))) (IMPLIES (OR (EQ (select2 $Heap@7 s@0 $ownerFrame) $PeerGroupPlaceholder) (OR (NOT (EQ (<: (select2 $Heap@7 (select2 $Heap@7 s@0 $ownerRef) $inv) (select2 $Heap@7 s@0 $ownerFrame)) |@true|)) (EQ (select2 $Heap@7 (select2 $Heap@7 s@0 $ownerRef) $localinv) ($BaseClass (select2 $Heap@7 s@0 $ownerFrame))))) (AND (LBLNEG |@28511| (FORALL ($pc) (PATS ($typeof $pc) (select2 $Heap@7 $pc $localinv) (select2 $Heap@7 $pc $inv) (select2 $Heap@7 $pc $ownerFrame) (select2 $Heap@7 $pc $ownerRef)) (QID unknown.0:0) (SKOLEMID 19) (IMPLIES (AND (AND (NEQ $pc nullObject) (EQ (select2 $Heap@7 $pc $allocated) |@true|)) (AND (EQ (select2 $Heap@7 $pc $ownerRef) (select2 $Heap@7 s@0 $ownerRef)) (EQ (select2 $Heap@7 $pc $ownerFrame) (select2 $Heap@7 s@0 $ownerFrame)))) (AND (EQ (select2 $Heap@7 $pc $inv) ($typeof $pc)) (EQ (select2 $Heap@7 $pc $localinv) ($typeof $pc)))))) (IMPLIES (FORALL ($pc) (PATS ($typeof $pc) (select2 $Heap@7 $pc $localinv) (select2 $Heap@7 $pc $inv) (select2 $Heap@7 $pc $ownerFrame) (select2 $Heap@7 $pc $ownerRef)) (QID unknown.0:0) (SKOLEMID 19) (IMPLIES (AND (AND (NEQ $pc nullObject) (EQ (select2 $Heap@7 $pc $allocated) |@true|)) (AND (EQ (select2 $Heap@7 $pc $ownerRef) (select2 $Heap@7 s@0 $ownerRef)) (EQ (select2 $Heap@7 $pc $ownerFrame) (select2 $Heap@7 s@0 $ownerFrame)))) (AND (EQ (select2 $Heap@7 $pc $inv) ($typeof $pc)) (EQ (select2 $Heap@7 $pc $localinv) ($typeof $pc))))) (AND (LBLNEG |@28647| (<= ($StringLength s@0) (select2 $Heap@7 this Chunker.ChunkSize))) (IMPLIES (<= ($StringLength s@0) (select2 $Heap@7 this Chunker.ChunkSize)) TRUE)))))))) (FORMULA block4437_correct (IMPLIES (LBLPOS |+5747| TRUE) (IMPLIES TRUE (IMPLIES TRUE ReallyLastGeneratedExit_correct)))) (FORMULA block4590_correct (IMPLIES (LBLPOS |+5742| TRUE) (IMPLIES TRUE (IMPLIES TRUE block4437_correct)))) (FORMULA block4607-2-block4590_correct (IMPLIES (LBLPOS |+25365| TRUE) (IMPLIES (EQ $Heap@7 $Heap@6) (IMPLIES (EQ stack0s@1 stack0s@0) (IMPLIES (EQ stack0o@4 stack0o@3) block4590_correct))))) (FORMULA block4607_correct (IMPLIES (LBLPOS |+5573| TRUE) (IMPLIES TRUE (IMPLIES (EQ ($IsTokenForType stack0s@0 Chunker) |@true|) (IMPLIES (EQ stack0o@3 (TypeObjectChunker)) (AND (LBLNEG |@28246| (NEQ this nullObject)) (IMPLIES (NEQ this nullObject) (AND (LBLNEG |@28252| (EQ (select2 $Heap@5 this $localinv) System.Object)) (IMPLIES (EQ (select2 $Heap@5 this $localinv) System.Object) (AND (LBLNEG |@28263| (< 0 (select2 $Heap@5 this 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) ($StringLength (select2 $Heap@5 this Chunker.src)))) (IMPLIES (<= (select2 $Heap@5 this Chunker.n) ($StringLength (select2 $Heap@5 this Chunker.src))) (AND (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 (select2 $Heap@5 $p $inv) ($typeof $p)) (EQ (select2 $Heap@5 $p $localinv) ($typeof $p)))))) (IMPLIES (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 (select2 $Heap@5 $p $inv) ($typeof $p)) (EQ (select2 $Heap@5 $p $localinv) ($typeof $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 (IMPLIES (EQ nullObjectnullObject) (IMPLIES TRUE block4607_correct))))) (FORMULA true4505to4607_correct (IMPLIES (LBLPOS |+5733| TRUE) (IMPLIES TRUE (IMPLIES (NEQ ($As nullObjectMicrosoft.Contracts.ICheckedException) nullObject) (IMPLIES TRUE block4607_correct))))) (FORMULA block4556-2-block4590_correct (IMPLIES (LBLPOS |+25363| TRUE) (IMPLIES (EQ $Heap@7 $Heap@5) (IMPLIES (EQ stack0s@1 stack0s) (IMPLIES (EQ stack0o@4 nullObject) block4590_correct))))) (FORMULA block4556_correct (IMPLIES (LBLPOS |+5737| TRUE) (IMPLIES TRUE (IMPLIES TRUE block4556-2-block4590_correct)))) (FORMULA false4505to4556_correct (IMPLIES (LBLPOS |+5735| TRUE) (IMPLIES TRUE (IMPLIES (EQ ($As nullObjectMicrosoft.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 nullObjectnullObject) (IMPLIES TRUE block4505_correct))))) (FORMULA block4471_correct (IMPLIES (LBLPOS |+5554| TRUE) (IMPLIES TRUE (IMPLIES 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 (EQ $Heap@5 (store2 $Heap@4 this Chunker.n stack0i@3)) (AND (LBLNEG |@28007| (OR (NOT (AND (EQ (<: (select2 $Heap@5 this $inv) Chunker) |@true|) (NEQ (select2 $Heap@5 this $localinv) ($BaseClassChunker)))) (< 0 (select2 $Heap@5 this Chunker.ChunkSize)))) (IMPLIES (OR (NOT (AND (EQ (<: (select2 $Heap@5 this $inv) Chunker) |@true|) (NEQ (select2 $Heap@5 this $localinv) ($BaseClassChunker)))) (< 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) ($BaseClassChunker)))) (<= 0 (select2 $Heap@5 this Chunker.n)))) (IMPLIES (OR (NOT (AND (EQ (<: (select2 $Heap@5 this $inv) Chunker) |@true|) (NEQ (select2 $Heap@5 this $localinv) ($BaseClassChunker)))) (<= 0 (select2 $Heap@5 this Chunker.n))) (AND (LBLNEG |@28103| (OR (NOT (AND (EQ (<: (select2 $Heap@5 this $inv) Chunker) |@true|) (NEQ (select2 $Heap@5 this $localinv) ($BaseClassChunker)))) (<= (select2 $Heap@5 this Chunker.n) ($StringLength (select2 $Heap@5 this Chunker.src))))) (IMPLIES (OR (NOT (AND $Heap@5 this Chunker.n) ($StringLength (select2 $Heap@5 this Chunker.src)))) (IMPLIES (EQ (IsHeap $Heap@5) |@true|) (IMPLIES 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_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 this nullObject) (IMPLIES (EQ stack1i@3 (select2 $Heap@1 this Chunker.n)) (AND (LBLNEG |@26955| (NEQ stack0o@1 nullObject)) (IMPLIES (NEQ 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 |@26968| (<= stack1i@3 ($StringLength stack0o@1))) (IMPLIES (<= stack1i@3 ($StringLength stack0o@1)) (AND (LBLNEG |@26976| (FORALL ($pc) (PATS ($typeof $pc) (select2 $Heap@1 $pc $localinv) (select2 $Heap@1 $pc $inv) (select2 $Heap@1 $pc $ownerFrame) (select2 $Heap@1 $pc $ownerRef)) (QID unknown.0:0) (SKOLEMID 27) (IMPLIES (AND (AND (NEQ $pc nullObject) (EQ (select2 $Heap@1 $pc $allocated) |@true|)) (AND (EQ (select2 $Heap@1 $pc $ownerRef) (select2 $Heap@1 stack0o@1 $ownerRef)) (EQ (select2 $Heap@1 $pc $ownerFrame) (select2 $Heap@1 (IMPLIES TRUE block4233_correct))))))))))))) (FORMULA block4063_correct (IMPLIES (LBLPOS |+2515| TRUE) (IMPLIES TRUE (IMPLIES TRUE block4216_correct)))) (FORMULA entry_correct (IMPLIES (LBLPOS |+2512| TRUE) (IMPLIES (EQ (IsHeap $Heap) |@true|) (IMPLIES (AND (EQ ($IsNotNull this Chunker) |@true|) (EQ (select2 $Heap this $allocated) |@true|)) (IMPLIES (AND (EQ ($IsNotNull $result System.String) |@true|) (EQ (select2 $Heap $result $allocated) |@true|)) (IMPLIES (AND (EQ ($Is local2 System.Exception) |@true|) (EQ (select2 $Heap local2 $allocated) |@true|)) (IMPLIES (AND (EQ ($Is s System.String) |@true|) (EQ (select2 $Heap s $allocated) |@true|)) (IMPLIES (AND (EQ ($Is return.valueSystem.String) |@true|) (EQ (select2 $Heap return.value $allocated) |@true|)) (IMPLIES (AND (EQ ($Is SS$Display.Return.LocalSystem.String) |@true|) (EQ (select2 $Heap SS$Display.Return.Local $allocated) |@true|)) (IMPLIES (EQ $PurityAxiomsCanBeAssumed |@true|) (IMPLIES (EQ $BeingConstructednullObject) (IMPLIES (OR (EQ (select2 $Heap this $ownerFrame) $PeerGroupPlaceholder) (OR (NOT (EQ (<: (select2 $Heap (select2 $Heap this $ownerRef) $inv) (select2 $Heap this $ownerFrame)) |@true|)) (EQ (select2 $Heap (select2 $Heap this $ownerRef) $localinv) ($BaseClass (select2 $Heap this $ownerFrame))))) (IMPLIES (FORALL ($pc) (PATS ($typeof $pc) (select2 $Heap $pc $localinv) (select2 $Heap $pc $inv) (select2 $Heap $pc $ownerFrame) (select2 $Heap $pc $ownerRef)) (QID unknown.0:0) (SKOLEMID 18) (IMPLIES (AND (AND (NEQ $pc nullObject) (EQ (select2 $Heap $pc $allocated) |@true|)) (AND (EQ (select2 $Heap $pc $ownerRef) (select2 $Heap this $ownerRef)) (EQ (select2 $Heap $pc $ownerFrame) (select2 $Heap this $ownerFrame)))) (AND (EQ (select2 $Heap $pc $inv) ($typeof $pc)) (EQ (select2 $Heap $pc $localinv) ($typeof $pc))))) (IMPLIES TRUE (IMPLIES TRUE block4063_correct)))))))))))))))) entry_correct) Verification condition
Further challenges • Extend structuring methodologies • Improve performance • …
Summary and conclusions • Spec# lets programmers work with contracts • type checking • run-time checking • program verification • Hardest challenge: programming methodology that • fits common programming idioms and • can be handled well by automatic prover • Education • Try it out! http://research.microsoft.com/specsharp DownloadSpec# from here