39
Spec# Spec# K. Rustan M. Leino K. Rustan M. Leino Senior Researcher Senior Researcher Programming Languages and Methods Programming Languages and Methods Microsoft Corporation Microsoft Corporation Joint work with: Mike Barnett, Robert DeLine, Manuel Joint work with: Mike Barnett, Robert DeLine, Manuel Fähndrich, Fähndrich, Wolfram Schulte, Herman Venter Wolfram Schulte, Herman Venter And interns: Bor-Yuh Evan Chang, Ádám Darvas, Bart Jacobs, And interns: Bor-Yuh Evan Chang, Ádám Darvas, Bart Jacobs, Daan Leijen, Angela Wallenburg Daan Leijen, Angela Wallenburg And visiting researchers: Francesco Logozzo, Peter Müller, And visiting researchers: Francesco Logozzo, Peter Müller, David A. Naumann, Arnd Poetzsch-Heffter David A. Naumann, Arnd Poetzsch-Heffter

Spec# K. Rustan M. Leino Senior Researcher Programming Languages and Methods Microsoft Corporation Joint work with: Mike Barnett, Robert DeLine, Manuel

  • View
    213

  • Download
    0

Embed Size (px)

Citation preview

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

Spec# Demo: ChunkerSpec# Demo: Chunker

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;;

}}

2. Preconditions2. Preconditions

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){ … }{ … }

}}

3. Object Invariants3. Object Invariants

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.