Spec# K. Rustan M. Leino Senior Researcher Programming Languages and Methods Microsoft Corporation...
-
date post
22-Dec-2015 -
Category
Documents
-
view
213 -
download
0
Transcript of Spec# K. Rustan M. Leino Senior Researcher Programming Languages and Methods Microsoft Corporation...
Spec#Spec#
K. Rustan M. LeinoK. Rustan M. LeinoSenior ResearcherSenior ResearcherProgramming Languages and MethodsProgramming Languages and MethodsMicrosoft CorporationMicrosoft CorporationJoint work with: Mike Barnett, Robert DeLine, Manuel Fähndrich,Joint work with: Mike Barnett, Robert DeLine, Manuel Fähndrich,Wolfram Schulte, Herman VenterWolfram Schulte, Herman VenterAnd interns: Bor-Yuh Evan Chang, Ádám Darvas, Bart Jacobs,And interns: Bor-Yuh Evan Chang, Ádám Darvas, Bart Jacobs,Daan Leijen, Angela WallenburgDaan Leijen, Angela WallenburgAnd visiting researchers: Francesco Logozzo, Peter Müller,And visiting researchers: Francesco Logozzo, Peter Müller,David A. Naumann, Arnd Poetzsch-HeffterDavid A. Naumann, Arnd Poetzsch-Heffter
Software Engineering ProblemSoftware Engineering Problem
BuildingBuilding and and maintainingmaintaining large systems large systems that are that are correctcorrect
ApproachApproach
SpecificationsSpecifications record design decisions record design decisionsBridge intent and codeBridge intent and code
ToolsTools amplify human effort amplify human effortManage detailsManage details
Find inconsistenciesFind inconsistencies
Ensure qualityEnsure quality
Research GoalsResearch Goals
BuildBuild the best such system we the best such system wecan build todaycan build today
ExperimentExperiment with the system to get with the system to geta feel for what it is like to usea feel for what it is like to use
Advance Advance the state of the artthe state of the art
Spec#Spec#
Experimental mix of contracts and tool supportExperimental mix of contracts and tool support
Aimed at experienced developers who knowAimed at experienced developers who knowthe high cost of testing and maintenancethe high cost of testing and maintenance
Superset of C#Superset of C#Non-null typesNon-null types
Pre- and postconditionsPre- and postconditions
Object invariantsObject invariants
Tool supportTool supportMore type checkingMore type checking
Compiler-emitted run-time checksCompiler-emitted run-time checks
Static program verificationStatic program verification
C#C#ContractsContracts
everywhereeverywhere
type type checkingchecking
static static verificationverification
into the futureinto the future
run-time run-time checkschecks
degree of degree of checking, effortchecking, effort
familiarfamiliar
Some Design IssuesSome Design Issues
1.1. Non-null typesNon-null types
2.2. C# compatibilityC# compatibility
3.3. PreconditionsPreconditions
4.4. Object invariantsObject invariants
5.5. Program verifier architectureProgram verifier architecture
6.6. Verification-condition generationVerification-condition generation
0. Non-null Types0. Non-null Types
T x; T x; The value of x is The value of x is null ornull or a reference to an a reference to an object whose type is a subtype of Tobject whose type is a subtype of T
T ! y; T ! y; The value of y is a reference to an object The value of y is a reference to an object whose type is a subtype of T, whose type is a subtype of T, not nullnot null
Non-null Escape Hatch: CastNon-null Escape Hatch: Cast
objectobject o; o;stringstring s; s;
……
stringstring! a = (! a = (stringstring!)o;!)o;
stringstring! b = (!)s;! b = (!)s;
publicpublic voidvoid M( T x ) { M( T x ) {
ifif (x == (x == nullnull) {) {……
} } elseelse { {intint y = ((!)x).f; y = ((!)x).f;… …
}}}}
Comparing Against NullComparing Against Null
publicpublic voidvoid M( T x ) { M( T x ) {
ifif (x == (x == nullnull) {) {……
} } elseelse { {intint y = x.f; y = x.f;… …
}}}}
Comparing Against NullComparing Against Null
Spec# performs a data-flow analysis to Spec# performs a data-flow analysis to allow this (similar to definite assignment)allow this (similar to definite assignment)
Non-null Instance FieldsNon-null Instance Fields
classclass C : B { C : B {T ! x;T ! x;publicpublic C(T ! y) C(T ! y):: basebase()(){{
thisthis.x = y;.x = y;}}publicpublic overrideoverride intint M() M()
{ { returnreturn x.f; } x.f; }
}}
Is this code type safe?Is this code type safe? No!No!
abstractabstract classclass B { B {publicpublic B() { B() { thisthis.M(); } .M(); }
publicpublic abstractabstract intint M(); M();
}}
null dereferencenull dereference
Non-null Instance FieldsNon-null Instance Fields
classclass C : B { C : B {T ! x;T ! x;publicpublic C(T ! y) C(T ! y){{
thisthis.x = y;.x = y;basebase(); ();
}}publicpublic overrideoverride intint M() M()
{ { returnreturn x.f; } x.f; }
}}
Spec# allows x to beSpec# allows x to beassigned before assigned before basebaseconstructor is calledconstructor is called
Other Non-null IssuesOther Non-null Issues
Comparing a field against nullComparing a field against nullif if ((thisthis.f != .f != nullnull) {) {// …// …thisthis.f.M(…);.f.M(…);}}
Static fieldsStatic fieldsstaticstatic T g = T g = newnew T(); T();
ArraysArraysT![ ] a = T![ ] a = newnew T![100]; T![100];
GenericsGenericsList<T!> myList = List<T!> myList = newnew List<T!>(); List<T!>();
Spec# is superset of C#Spec# is superset of C#
From C# to Spec#From C# to Spec#Accept every C# programAccept every C# program
Compile it to have the same behaviorCompile it to have the same behavior
ConsequencesConsequences““Possible null dereference” is just a warningPossible null dereference” is just a warning
““Must initialize non-null fields before calling Must initialize non-null fields before calling base constructor” is an errorbase constructor” is an error
Support for out-of-band contractsSupport for out-of-band contracts
1. C# Compatibility1. C# Compatibility
From Spec# To C#From Spec# To C#Or: Leveraging wiz-bang features of Visual Or: Leveraging wiz-bang features of Visual Studio 2005Studio 2005
classclass B : A { B : A {stringstring! src;! src;publicpublic B( B(stringstring! source, ! source, intint x)x)
//^ //^ requiresrequires 0 <= x; 0 <= x;{{
thisthis.src = source;.src = source;basebase(x);(x);
}}
From Spec# To C#From Spec# To C#Or: Leveraging wiz-bang featuresOr: Leveraging wiz-bang featuresof Visual Studio 2005of Visual Studio 2005
classclass B : A { B : A {stringstring/*!*//*!*/ src; src;publicpublic B( B(stringstring/*!*//*!*/ source, source, intint x)x)
//^ //^ requiresrequires 0 <= x; 0 <= x; : : basebase(x)(x){{
thisthis.src = source;.src = source;//^ //^ basebase;;
}}
StringBuilder.Append Method (Char[StringBuilder.Append Method (Char[ ], Int32, Int32)], Int32, Int32)Appends the string representation of a specified subarray of Unicode characters to the end of this instanceAppends the string representation of a specified subarray of Unicode characters to the end of this instance
publicpublic StringBuilder StringBuilder AppendAppend((charchar[] [] valuevalue, , intint startIndexstartIndex, , intint charCountcharCount););
ParametersParameters
valuevalueA character arrayA character array
startIndexstartIndexThe starting position in The starting position in valuevalue
charCountcharCountThe number of characters appendThe number of characters append
Return ValueReturn Value
A reference to this instance after the append operation has occurredA reference to this instance after the append operation has occurred
ExceptionsExceptions
Contracts TodayContracts Today
Exception TypeException Type ConditionCondition
ArgumentNullExceptionArgumentNullException valuevalue is a null reference, and is a null reference, and startIndexstartIndex and and charCountcharCount are not zero are not zero
ArgumentOutOfRangeExceptionArgumentOutOfRangeException charCountcharCount is less than zero is less than zero
-or--or-
startIndexstartIndex is less than zero is less than zero
-or--or-
startIndexstartIndex + + charCountcharCount is less than the length of is less than the length of valuevalue
Contract In Spec#Contract In Spec#
publicpublic StringBuilder Append( StringBuilder Append(charchar[ ] value, [ ] value, intint startIndex, startIndex,intint charCount ); charCount );
requiresrequires value == value == nullnull ==> startIndex == 0 && charCount ==> startIndex == 0 && charCount == 0;== 0;
requiresrequires 0 <= startIndex;0 <= startIndex;
requiresrequires 0 <= charCount; 0 <= charCount;
requiresrequires value == value == nullnull || || startIndex + charCount <= value.Length; startIndex + charCount <= value.Length;
Exception TypeException Type ConditionCondition
ArgumentNullExceptionArgumentNullException valuevalue is a null reference, and is a null reference, and startIndexstartIndex and and charCountcharCount are not zero are not zero
ArgumentOutOfRangeExceptionArgumentOutOfRangeException charCountcharCount is less than zero is less than zero
-or--or-
startIndexstartIndex is less than zero is less than zero
-or--or-
startIndexstartIndex + + charCountcharCount is less than the length of is less than the length of valuevalue
Otherwise ClausesOtherwise Clauses
publicpublic StringBuilder Append( StringBuilder Append(charchar[ ] value, [ ] value, intint startIndex, startIndex,intint charCount ); charCount );
requiresrequires value == value == nullnull ==> startIndex == 0 && charCount == ==> startIndex == 0 && charCount == 00
otherwiseotherwise ArgumentNullException; ArgumentNullException;
requiresrequires 0 <= startIndex0 <= startIndexotherwiseotherwise ArgumentOutOfRangeException; ArgumentOutOfRangeException;
… …
Exception TypeException Type ConditionCondition
ArgumentNullExceptionArgumentNullException valuevalue is a null reference, and is a null reference, and startIndexstartIndex and and charCountcharCount are not zero are not zero
ArgumentOutOfRangeExceptionArgumentOutOfRangeException charCountcharCount is less than zero is less than zero
-or--or-
startIndexstartIndex is less than zero is less than zero
-or--or-
startIndexstartIndex + + charCountcharCount is less than the length of is less than the length of valuevalue
Inheriting ContractsInheriting Contracts
interfaceinterface J { J {voidvoid M( M(intint x); x); requiresrequires P; P;
}}
classclass A { A {public abstract voidpublic abstract void M( M(intint x); x);
requiresrequires Q; Q;}}
classclass B : A, J { B : A, J {public override voidpublic override void M( M(intint x) x){ … }{ … }
}}
When Do Object Invariants Hold?When Do Object Invariants Hold?
classclass C { C {
privateprivate intint x; x;privateprivate intint y; y;
invariantinvariant x < y; x < y;
publicpublic C() { x = 0; y = 1; } C() { x = 0; y = 1; }
publicpublic voidvoid M() M(){{
intint t = 100 / (y – x); t = 100 / (y – x);x = x + 1;x = x + 1;P(t);P(t);y = y + 1;y = y + 1;
}}
……
}}
invariant assumed to holdinvariant assumed to holdon entry to methodon entry to method
invariant checked to holdinvariant checked to holdon exit from methodon exit from method
invariant checked to holdinvariant checked to holdat end of constructorat end of constructor
invariant may beinvariant may betemporarily broken heretemporarily broken here
invariant is restored hereinvariant is restored here
what if P calls back into M?what if P calls back into M?
Object StatesObject States
MutableMutableObject invariant may not holdObject invariant may not hold
Field updates allowedField updates allowed
ValidValidObject invariant holdsObject invariant holds
Field updates not allowedField updates not allowed
Valid Versus Mutable ObjectsValid Versus Mutable Objectsclassclass C { C {
privateprivate intint x; x;privateprivate intint y; y;invariantinvariant x < y; x < y;
publicpublic voidvoid M() M()requiresrequires thisthis.inv == .inv ==
Valid;Valid;{{
exposeexpose ( (thisthis) {) {intint t = 100 / (y – x); t = 100 / (y – x);x = x + 1;x = x + 1;P(t);P(t);y = y + 1;y = y + 1;
}}}}……
}}
represent explicitlyrepresent explicitlythat invariant holdsthat invariant holds(without revealing(without revealing
what the invariant is)what the invariant is)
change this.invchange this.invfrom Valid to Mutablefrom Valid to Mutable
check invariant;check invariant;then, change this.invthen, change this.invfrom Mutable to Validfrom Mutable to Valid
field updates allowedfield updates allowedonly on Mutable objectsonly on Mutable objects
Summary Of Object InvariantsSummary Of Object Invariants
invariantinvariant … …
invinv : { Mutable, Valid } : { Mutable, Valid }
exposeexpose
updates of o.f require o.updates of o.f require o.invinv = Mutable = Mutable
((o o ・ ・ o.inv = Mutable o.inv = Mutable Inv (o)) Inv (o))
4. Spec# Verifier Architecture4. Spec# Verifier Architecture
V.C. generatorV.C. generator
automaticautomatictheorem provertheorem prover
verification conditionverification condition
Spec#Spec#
““correct” or list of errorscorrect” or list of errors
Spec# compilerSpec# compiler
MSIL (“bytecode”)MSIL (“bytecode”)
bytecode translatorbytecode translator
Boogie PLBoogie PL
inference engineinference engine
Spec# program verifier (aka Boogie)Spec# program verifier (aka Boogie)
BoogiePLBoogiePL
Intermediate languageIntermediate languageTheory partTheory part
Imperative partImperative part
Semantics of Spec# is encodedSemantics of Spec# is encodedin BoogiePLin BoogiePL
Can be used for other program-Can be used for other program-verification tasks, like verifyingverification tasks, like verifyingother source languagesother source languages
Example BoogiePLExample BoogiePL
varvar $Heap: [ $Heap: [refref,,namename]]anyany wherewhere IsHeap($Heap); IsHeap($Heap);functionfunction IsHeap(h: [IsHeap(h: [refref,,namename]]anyany) ) returnsreturns ( (boolbool););
constconst Chunker: Chunker: namename;;axiomaxiom Chunker <: System.Object; Chunker <: System.Object;
constconst Chunker.n: Chunker.n: namename;;functionfunction DeclType(field: DeclType(field: namename) ) returnsreturns (class: (class: namename););axiomaxiom DeclType(Chunker.n) = Chunker; DeclType(Chunker.n) = Chunker;
constconst $allocated: $allocated: namename;;axiomaxiom ( ( h: [ h: [refref,,namename]]anyany, o: , o: refref, f: , f: namename • •
IsHeap(h) IsHeap(h) h[o, $allocated] h[o, $allocated] h[h[o, f], h[h[o, f],$allocated]);$allocated]);
constconst $inv: $inv: namename;;axiomaxiom ( ( $oi: $oi: refref, $h: [, $h: [refref,,namename]]anyany • •
IsHeap($h) IsHeap($h) $h[$oi, $inv] <: Chunker $h[$oi, $inv] <: Chunker0 < $h[$oi, Chunker.ChunkSize] 0 < $h[$oi, Chunker.ChunkSize] 0 ≤ $h[$oi, Chunker.n] 0 ≤ $h[$oi, Chunker.n] $h[$oi, Chunker.n] ≤ $Length($h[$oi, Chunker.src]));$h[$oi, Chunker.n] ≤ $Length($h[$oi, Chunker.src]));
Example BoogiePLExample BoogiePL
procedureprocedure Chunker.NextChunk(this: Chunker.NextChunk(this: refref) ) returnsreturns ($result: ($result: refref););
requiresrequires $Heap[this, $inv] = Chunker;$Heap[this, $inv] = Chunker;
requiresrequires $Heap[this, $ownerFrame] = $PeerGroupPlaceholder $Heap[this, $ownerFrame] = $PeerGroupPlaceholder ¬($Heap[$Heap[this, $ownerRef], $inv] <: $Heap[this, $ownerFrame]);¬($Heap[$Heap[this, $ownerRef], $inv] <: $Heap[this, $ownerFrame]);
freefree requiresrequires $Heap[this, $allocated] = $Heap[this, $allocated] = truetrue $IsNotNull(this, Chunker); $IsNotNull(this, Chunker);
modifiesmodifies $Heap; $Heap;
ensuresensures $Length($result) ≤ $Heap[this, Chunker.ChunkSize]; $Length($result) ≤ $Heap[this, Chunker.ChunkSize];
ensuresensures ( ( $pc: $pc: refref • $pc ≠ • $pc ≠ nullnull $Heap[$pc, $allocated] = $Heap[$pc, $allocated] = truetrue $Heap[$pc, $ownerRef] = $Heap[$result, $ownerRef] $Heap[$pc, $ownerRef] = $Heap[$result, $ownerRef] $Heap[$pc, $ownerFrame] = $Heap[$result, $ownerFrame]$Heap[$pc, $ownerFrame] = $Heap[$result, $ownerFrame]($Heap[$pc, $ownerFrame] = $PeerGroupPlaceholder ($Heap[$pc, $ownerFrame] = $PeerGroupPlaceholder
¬($Heap[$Heap[$pc, $ownerRef], $inv] <: $Heap[$pc, $ownerFrame])) ¬($Heap[$Heap[$pc, $ownerRef], $inv] <: $Heap[$pc, $ownerFrame])) $Heap[$pc, $inv] = $typeof($pc));$Heap[$pc, $inv] = $typeof($pc));
freefree ensuresensures $Heap[$result, $allocated] = $Heap[$result, $allocated] = truetrue $IsNotNull($result, System.String); $IsNotNull($result, System.String);
freefree ensuresensures ( ( $o: $o: refref • $o ≠ • $o ≠ nullnull ¬ ¬oldold($Heap)[$o, $allocated] ($Heap)[$o, $allocated] $Heap[$o, $allocated] $Heap[$o, $allocated] $Heap[$o, $inv] = $typeof($o)); $Heap[$o, $inv] = $typeof($o));
ensuresensures ( ( $o: $o: refref • $o ≠ • $o ≠ nullnull oldold($Heap)[$o, $allocated] = ($Heap)[$o, $allocated] = truetrue oldold($Heap)[$Heap[$o, $ownerRef], $allocated] = ($Heap)[$Heap[$o, $ownerRef], $allocated] = truetrueoldold($Heap)[$o, $ownerRef] = $Heap[$o, $ownerRef] ($Heap)[$o, $ownerRef] = $Heap[$o, $ownerRef] oldold($Heap)[$o, $ownerFrame] = $Heap[$o, $ownerFrame]);($Heap)[$o, $ownerFrame] = $Heap[$o, $ownerFrame]);
freefree ensuresensures ( ( $o: $o: refref, $f: , $f: namename • $f ≠ $inv • $f ≠ $inv $o ≠ $o ≠ nullnull oldold($Heap)[$o, $allocated] = ($Heap)[$o, $allocated] = truetrue ((oldold($Heap)[$o, $ownerFrame] = $PeerGroupPlaceholder ($Heap)[$o, $ownerFrame] = $PeerGroupPlaceholder
¬(¬(oldold($Heap)[($Heap)[oldold($Heap)[$o, $ownerRef], $inv] <: ($Heap)[$o, $ownerRef], $inv] <: oldold($Heap)[$o, $ownerFrame])) ($Heap)[$o, $ownerFrame])) (¬IsStaticField($f) (¬IsStaticField($f) ¬IsDirectlyModifiableField($f)) ¬IsDirectlyModifiableField($f)) oldold($Heap)[$o, $f] = $Heap[$o, $f]);($Heap)[$o, $f] = $Heap[$o, $f]);
freefree ensuresensures ( ( $o: $o: refref • • oldold($Heap)[$o, $inv] = $Heap[$o, $inv] ($Heap)[$o, $inv] = $Heap[$o, $inv] oldold($Heap)[$o, $allocated] ≠ ($Heap)[$o, $allocated] ≠ truetrue););
freefree ensuresensures ( ( $o: $o: refref • • oldold($Heap)[$o, $allocated] ($Heap)[$o, $allocated] $Heap[$o, $allocated]); $Heap[$o, $allocated]);
Example BoogiePLExample BoogiePL
implementationimplementation Chunker.NextChunk(this: Chunker.NextChunk(this: refref) ) returnsreturns ($result: ($result: refref)){{ varvar temp0: temp0: refref, local4: , local4: refref, stack0i: , stack0i: intint, stack1i: , stack1i: intint, ,
stack1o: stack1o: refref,,stack0b: stack0b: boolbool, stack0o: , stack0o: refref, stack2i: , stack2i: intint, s: , s: refref, , return.value: return.value: refref,,SS$Display.Return.Local: SS$Display.Return.Local: refref;;
entry:entry: // …// … // ----- load field ----- Chunker.ssc(14,7)// ----- load field ----- Chunker.ssc(14,7) assertassert this ≠ this ≠ nullnull;; stack1o := $Heap[this, Chunker.src];stack1o := $Heap[this, Chunker.src]; // …// … // ----- binary operator ----- Chunker.ssc(14,7)// ----- binary operator ----- Chunker.ssc(14,7) stack0b := stack0i > stack1i;stack0b := stack0i > stack1i; // ----- branch ----- Chunker.ssc(14,7)// ----- branch ----- Chunker.ssc(14,7) gotogoto true5814to5848, false5814to5831; true5814to5848, false5814to5831;
true5814to5848:true5814to5848: assumeassume stack0b = stack0b = truetrue;; … …
Example BoogiePLExample BoogiePL
// ----- call ----- Chunker.ssc(17,9)// ----- call ----- Chunker.ssc(17,9) assertassert stack0o ≠ stack0o ≠ nullnull;; callcall s := s :=
System.String.Substring$System.Int32(stack0o, System.String.Substring$System.Int32(stack0o, stack1i);stack1i);
// …// … // ----- store field ----- Chunker.ssc(19,7)// ----- store field ----- Chunker.ssc(19,7) assertassert this ≠ this ≠ nullnull;; assertassert ¬($Heap[this, $inv] <: Chunker); ¬($Heap[this, $inv] <: Chunker); $Heap[this, Chunker.n] := stack0i;$Heap[this, Chunker.n] := stack0i; // …// … // ----- return// ----- return $result := stack0o;$result := stack0o; returnreturn;;}}
5. Verification Conditions5. Verification Conditions
Automatic theorem proverAutomatic theorem proverCan be hidden from programmerCan be hidden from programmer
Generates counterexamplesGenerates counterexamples
Interactive theorem proverInteractive theorem proverRequires gurusRequires gurus
Not limited by built-in decision proceduresNot limited by built-in decision procedures
Performance ConsiderationsPerformance Considerations
Generate verification conditions that Generate verification conditions that the theorem prover can handle quicklythe theorem prover can handle quickly
““Efficient” encodings of axiomsEfficient” encodings of axioms
““Efficient” weakest preconditionsEfficient” weakest preconditions
Initial Verifier ExperienceInitial Verifier Experience
Pilot production projectPilot production project““It changes how you think”It changes how you think”
Several smaller (300-1500 lines)Several smaller (300-1500 lines)case studiescase studies
Parts of Spec# program verifierParts of Spec# program verifier
External academic useExternal academic use
ConclusionsConclusions
Because of tool support, we’re ready for programmingBecause of tool support, we’re ready for programmingat the next level of rigorat the next level of rigor
Current workCurrent workSpecification/programming/verification methodologySpecification/programming/verification methodology
PerformancePerformance
Technology transferTechnology transfer
Engineering effortEngineering effort
Technology sharingTechnology sharingTeachingTeaching
Case studiesCase studies
BoogiePL as common intermediate logicBoogiePL as common intermediate logic
http://research.microsoft.com/~leino
http://research.microsoft.com/specsharp
Download Spec#Download Spec#
from herefrom here
© 2006 Microsoft Corporation. All rights reserved.Microsoft, Windows, Windows Vista and other product names are or may be registered trademarks and/or trademarks in the U.S. and/or other countries.
The information herein is for informational purposes only and represents the current view of Microsoft Corporation as of the date of this presentation.Because Microsoft must respond to changing market conditions, it should not be interpreted to be a commitment on the part of Microsoft,
and Microsoft cannot guarantee the accuracy of any information provided after the date of this presentation.MICROSOFT MAKES NO WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, AS TO THE INFORMATION IN THIS PRESENTATION.