software model checking with slam l.
Download
Skip this Video
Loading SlideShow in 5 Seconds..
Software Model Checking with SLAM PowerPoint Presentation
Download Presentation
Software Model Checking with SLAM

Loading in 2 Seconds...

play fullscreen
1 / 98

Software Model Checking with SLAM - PowerPoint PPT Presentation


  • 321 Views
  • Uploaded on

Software Model Checking with SLAM. Thomas Ball Testing, Verification and Measurement Sriram K. Rajamani Software Productivity Tools Microsoft Research http://research.microsoft.com/slam/. People behind SLAM. Summer interns Sagar Chaki, Todd Millstein, Rupak Majumdar (2000)

loader
I am the owner, or an agent authorized to act on behalf of the owner, of the copyrighted work described.
capcha
Download Presentation

PowerPoint Slideshow about 'Software Model Checking with SLAM' - Albert_Lan


An Image/Link below is provided (as is) to download presentation

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.


- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -
Presentation Transcript
software model checking with slam

Software Model Checking withSLAM

Thomas Ball

Testing, Verification and Measurement

Sriram K. Rajamani

Software Productivity Tools

Microsoft Research

http://research.microsoft.com/slam/

people behind slam
People behind SLAM

Summer interns

  • Sagar Chaki, Todd Millstein, Rupak Majumdar (2000)
  • Satyaki Das, Wes Weimer, Robby (2001)
  • Jakob Lichtenberg, Mayur Naik (2002)

Visitors

  • Giorgio Delzanno, Andreas Podelski, Stefan Schwoon

Windows Partners

  • Byron Cook, Vladimir Levin, Abdullah Ustuner
outline
Outline
  • Part I: Overview (30 min)
    • overview of SLAM process
    • demonstration (Static Driver Verifier)
    • lessons learned
  • Part II: Basic SLAM (1 hour)
    • foundations
    • basic algorithms (no pointers)
  • Part III: Advanced Topics (30 min)
    • pointers + procedures
    • imprecision in aliasing and mod analysis
what is slam
What is SLAM?

SLAM is a software model checking project at Microsoft Research

  • Goal: Check C programs (system software) against safety properties using model checking
  • Application domain: device drivers

Starting to be used internally inside Windows

  • Working on making this into a product
slide6

Read for

understanding

Drive testing

tools

Precise

API Usage Rules

(SLIC)

New API rules

Defects

Software Model

Checking

100% path

coverage

Rules

Static Driver Verifier

Development

Testing

Source Code

slam software model checking
SLAM – Software Model Checking
  • SLAM innovations
    • boolean programs: a new model for software
    • model creation (c2bp)
    • model checking (bebop)
    • model refinement (newton)
  • SLAM toolkit
    • built on MSR program analysis infrastructure
slide8
SLIC
  • Finite state language for stating rules
    • monitors behavior of C code
    • temporal safety properties (security automata)
    • familiar C syntax
  • Suitable for expressing control-dominated properties
    • e.g. proper sequence of events
    • can encode data values inside state
state machine for locking

Locking Rule in SLIC

state {

enum {Locked,Unlocked}

s = Unlocked;

}

KeAcquireSpinLock.entry {

if (s==Locked) abort;

else s = Locked;

}

KeReleaseSpinLock.entry {

if (s==Unlocked) abort;

else s = Unlocked;

}

State Machine for Locking

Rel

Acq

Unlocked

Locked

Rel

Acq

Error

the slam process
The SLAM Process

boolean

program

c2bp

prog. P

prog. P’

slic

bebop

SLIC rule

predicates

path

newton

example
Example

Does this code

obey the

locking rule?

do {

KeAcquireSpinLock();

nPacketsOld = nPackets;

if(request){

request = request->Next;

KeReleaseSpinLock();

nPackets++;

}

} while (nPackets != nPacketsOld);

KeReleaseSpinLock();

example12
Example

Model checking

boolean program

(bebop)

do {

KeAcquireSpinLock();

if(*){

KeReleaseSpinLock();

}

} while (*);

KeReleaseSpinLock();

U

L

L

L

U

L

U

L

U

U

E

example13
Example

Is error path feasible

in C program?

(newton)

do {

KeAcquireSpinLock();

nPacketsOld = nPackets;

if(request){

request = request->Next;

KeReleaseSpinLock();

nPackets++;

}

} while (nPackets != nPacketsOld);

KeReleaseSpinLock();

U

L

L

L

U

L

U

L

U

U

E

example14
Example

Add new predicate

to boolean program

(c2bp)

b : (nPacketsOld == nPackets)

do {

KeAcquireSpinLock();

nPacketsOld = nPackets;b = true;

if(request){

request = request->Next;

KeReleaseSpinLock();

nPackets++;b = b ? false : *;

}

} while (nPackets != nPacketsOld); !b

KeReleaseSpinLock();

U

L

L

L

U

L

U

L

U

U

E

example15
Example

Model checking

refined

boolean program

(bebop)

b : (nPacketsOld == nPackets)

do {

KeAcquireSpinLock();

b = true;

if(*){

KeReleaseSpinLock();

b = b ? false : *;

}

} while ( !b);

KeReleaseSpinLock();

U

L

b

L

b

L

b

U

b

!b

L

U

b

L

U

b

U

E

example16
Example

Model checking

refined

boolean program

(bebop)

b : (nPacketsOld == nPackets)

do {

KeAcquireSpinLock();

b = true;

if(*){

KeReleaseSpinLock();

b = b ? false : *;

}

} while ( !b);

KeReleaseSpinLock();

U

L

b

L

b

L

b

U

b

!b

L

U

b

L

b

U

observations about slam
Observations about SLAM
  • Automatic discovery of invariants
    • driven by property and a finite set of (false) execution paths
    • predicates are not invariants, but observations
    • abstraction + model checking computes inductive invariants (boolean combinations of observations)
  • A hybrid dynamic/static analysis
    • newton executes path through C code symbolically
    • c2bp+bebop explore all paths through abstraction
  • A new form of program slicing
    • program code and data not relevant to property are dropped
    • non-determinism allows slices to have more behaviors
part i demo
Part I: Demo

Static Driver Verifier results

slide20
SLAM
  • Boolean program model has proved itself
  • Successful for domain of device drivers
    • control-dominated safety properties
    • few boolean variables needed to do proof or find real counterexamples
  • Counterexample-driven refinement
    • terminates in practice
    • incompleteness of theorem prover not an issue
what is hard
What is hard?
  • Abstracting
    • from a language with pointers (C)
    • to one without pointers (boolean programs)
  • All side effects need to be modeled by copying (as in dataflow)
  • Open environment problem
what stayed fixed
What stayed fixed?
  • Boolean program model
  • Basic tool flow
  • Repercussions:
    • newton has to copy between scopes
    • c2bp has to model side-effects by value-result
    • finite depth precision on the heap is all boolean programs can do
what changed
What changed?
  • Interface between newton and c2bp
  • We now use predicates for doing more things
      • refine alias precision via aliasing predicates
      • newton helps resolve pointer aliasing imprecision in c2bp
scaling slam
Scaling SLAM
  • Largest driver we have processed has ~60K lines of code
  • Largest abstractions we have analyzed have several hundred boolean variables
  • Routinely get results after 20-30 iterations
  • Out of 672 runs we do daily, 607 terminate within 20 minutes
scale and slam components
Scale and SLAM components
  • Out of 67 runs that time out, tools that take longest time:
    • bebop: 50, c2bp: 10, newton: 5, constrain: 2
  • C2bp:
    • fast predicate abstraction (fastF) and incremental predicate abstraction (constrain)
    • re-use across iterations
  • Newton:
    • biggest problems are due to scope-copying
  • Bebop:
    • biggest issue is no re-use across iterations
    • solution in the works
slam status
SLAM Status
  • 2000-2001
    • foundations, algorithms, prototyping
    • papers in CAV, PLDI, POPL, SPIN, TACAS
  • March 2002
    • Bill Gates review
  • May 2002
    • Windows committed to hire two people with model checking background to support Static Driver Verifier (SLAM+driver rules)
  • July 2002
    • running SLAM on 100+ drivers, 20+ properties
  • September 3, 2002
    • made initial release of SDV to Windows (friends and family)
  • April 1, 2003
    • made wide release of SDV to Windows (any internal driver developer)
slide28
C-

Types  ::= void | bool | int | ref 

Expressions e ::= c | x | e1 op e2 | &x | *x

LExpression l ::= x | *x

Declaration d ::=  x1,x2 ,…,xn

Statements s ::= skip | goto L1,L2 …Ln | L: s

| assume(e)

| l = e

| l = f (e1 ,e2 ,…,en)

| return x

| s1; s2 ;… ; sn

Procedures p ::=f (x1: 1,x2 : 2,…,xn : n )

Program g ::= d1 d2 … dn p1 p2 … pn

slide29
C--

Types  ::= void | bool | int

Expressions e ::= c | x | e1 op e2

LExpression l ::= x

Declaration d ::=  x1,x2 ,…,xn

Statements s ::= skip | goto L1,L2 …Ln | L: s

| assume(e)

| l = e

| f (e1 ,e2 ,…,en)

| return

| s1; s2 ;… ; sn

Procedures p ::=f (x1: 1,x2 : 2,…,xn : n )

Program g ::= d1 d2 … dn p1 p2 … pn

slide30
BP

Types  ::= void | bool

Expressions e ::= c | x | e1 op e2

LExpression l ::= x

Declaration d ::=  x1,x2 ,…,xn

Statements s ::= skip | goto L1,L2 …Ln | L: s

| assume(e)

| l = e

| f (e1 ,e2 ,…,en)

| return

| s1; s2 ;… ; sn

Procedures p ::=f (x1: 1,x2 : 2,…,xn : n )

Program g ::= d1 d2 … dn p1 p2 … pn

syntactic sugar
Syntactic sugar

goto L1, L2;

L1: assume(e);

S1;

goto L3;

L2: assume(!e);

S2;

goto L3;

L3: S3;

if (e) {

S1;

} else {

S2;

}

S3;

example in c
Example, in C

void cmp (int a , int b) {

if (a == b)

g = 0;

else

g = 1;

}

int g;

main(int x, int y){

cmp(x, y);

if (!g) {

if (x != y)

assert(0);

}

}

example in c33
Example, in C--

int g;

main(int x, int y){

cmp(x, y);

assume(!g);

assume(x != y)

assert(0);

}

void cmp(int a , int b) {

goto L1, L2;

L1: assume(a==b);

g = 0;

return;

L2: assume(a!=b);

g = 1;

return;

}

the slam process34
The SLAM Process

boolean

program

c2bp

prog. P

prog. P’

slic

bebop

SLIC rule

predicates

path

newton

c2bp predicate abstraction for c programs
c2bp: Predicate Abstraction for C Programs

Given

  • P : a C program
  • F = {e1,...,en}
    • each ei a pure boolean expression
    • each ei represents set of states for which ei is true

Produce a boolean programB(P,F)

  • same control-flow structure as P
  • boolean vars {b1,...,bn} to match {e1,...,en}
  • properties true of B(P,F) are true of P
assumptions
Assumptions

Given

  • P : a C program
  • F = {e1,...,en}
    • each eia pure boolean expression
    • each eirepresents set of states for which ei is true
  • Assume: each ei uses either:
    • only globals (global predicate)
    • local variables from some procedure (local predicate for that procedure)
  • Mixed predicates:
    • predicates using both local variables and global variables
    • complicate “return” processing
    • covered in advanced topics
c2bp algorithm
C2bp Algorithm
  • Performs modular abstraction
    • abstracts each procedure in isolation
  • Within each procedure, abstracts each statement in isolation
    • no control-flow analysis
    • no need for loop invariants
slide38

int g;

main(int x, int y){

cmp(x, y);

assume(!g);

assume(x != y)

assert(0);

}

void cmp (int a , int b) {

goto L1, L2

L1: assume(a==b);

g = 0;

return;

L2: assume(a!=b);

g = 1;

return;

}

Preds: {x==y}

{g==0}

{a==b}

slide39

int g;

main(int x, int y){

cmp(x, y);

assume(!g);

assume(x != y)

assert(0);

}

void cmp (int a , int b) {

goto L1, L2

L1: assume(a==b);

g = 0;

return;

L2: assume(a!=b);

g = 1;

return;

}

void cmp ( {a==b} ) {

}

decl {g==0} ;

main( {x==y} ) {

}

Preds: {x==y}

{g==0}

{a==b}

slide40

int g;

main(int x, int y){

cmp(x, y);

assume(!g);

assume(x != y)

assert(0);

}

void equal (int a , int b) {

goto L1, L2

L1: assume(a==b);

g = 0;

return;

L2: assume(a!=b);

g = 1;

return;

}

void cmp ( {a==b} ) {

goto L1, L2;

L1: assume( {a==b} );

{g==0} = T;

return;

L2: assume( !{a==b} );

{g==0} = F;

return;

}

decl {g==0} ;

main( {x==y} ) {

cmp( {x==y} );

assume( {g==0} );

assume( !{x==y} );

assert(0);

}

Preds: {x==y}

{g==0}

{a==b}

slide41
C--

Types  ::= void | bool | int

Expressions e ::= c | x | e1 op e2

LExpression l ::= x

Declaration d ::=  x1,x2 ,…,xn

Statements s ::= skip | goto L1,L2 …Ln | L: s

| assume(e)

| l= e

| f (e1 ,e2 ,…,en)

| return

| s1; s2 ;… ; sn

Procedures p ::=f (x1: 1,x2 : 2,…,xn : n )

Program g ::= d1 d2 … dn p1 p2 … pn

abstracting assigns via wp
Abstracting Assigns via WP
  • Statement y=y+1 and F={ y<4, y<5 }
    • {y<4},{y<5} = ((!{y<5} || !{y<4}) ? F : *), {y<4} ;
  • WP(x=e,Q) = Q[x -> e]
  • WP(y=y+1, y<5) =

(y<5) [y -> y+1] =

(y+1<5) =

(y<4)

wp problem
WP Problem
  • WP(s, ei) not always expressible via { e1,...,en}
  • Example
    • F = { x==0, x==1, x<5}
    • WP( x=x+1,x<5 ) = x<4
    • Best possible: x==0 || x==1
abstracting expressions via f
Abstracting Expressions via F
  • F = { e1,...,en}
  • ImpliesF(e)
    • best boolean function over F that impliese
  • ImpliedByF(e)
    • best boolean function over F implied bye
    • ImpliedByF(e) = !ImpliesF(!e)
implies f e and impliedby f e

e

ImpliedByF(e)

ImpliesF(e)

ImpliesF(e) and ImpliedByF(e)
computing implies f e
Computing ImpliesF(e)
  • minterm m = d1 && ... && dn
    • where di = ei or di = !ei
  • ImpliesF(e)
    • disjunction of all minterms that imply e
  • Naïve approach
    • generate all 2n possible minterms
    • for each minterm m, use decision procedure to check validity of each implication me
  • Many optimizations possible
abstracting assignments
Abstracting Assignments
  • if ImpliesF(WP(s, ei)) is true before s then
    • ei is true after s
  • if ImpliesF(WP(s, !ei)) is true before s then
    • ei is false after s

{ei} = ImpliesF(WP(s, ei)) ? true :

ImpliesF(WP(s, !ei)) ? false

: *;

assignment example
Assignment Example

Statement in P: Predicates in E:

y = y+1; {x==y}

Weakest Precondition:

WP(y=y+1, x==y) = x==y+1

ImpliesF( x==y+1 ) = false

ImpliesF( x!=y+1 ) = x==y

Abstraction of assignment in B:

{x==y} = {x==y} ? false : *;

absracting assumes
Absracting Assumes
  • WP( assume(e) , Q) = eQ
  • assume(e) is abstracted to:

assume( ImpliedByF(e) )

  • Example:

F = {x==2, x<5}

assume(x < 2) is abstracted to:

assume( {x<5} && !{x==2} )

abstracting procedures
Abstracting Procedures
  • Each predicate in F is annotated as being either global or local to a particular procedure
  • Procedures abstracted in two passes:
    • a signature is produced for each procedure in isolation
    • procedure calls are abstracted given the callees’ signatures
abstracting a procedure call
Abstracting a procedure call
  • Procedure call
    • a sequence of assignments from actuals to formals
    • see assignment abstraction
  • Procedure return
    • NOP for C-- with assumption that all predicates mention either only globals or only locals
    • with pointers and with mixed predicates:
      • Most complicated part of c2bp
      • Covered in the advanced topics section
slide52

int g;

main(int x, int y){

cmp(x, y);

assume(!g);

assume(x != y)

assert(0);

}

void cmp (int a , int b) {

Goto L1, L2

L1: assume(a==b);

g = 0;

return;

L2: assume(a!=b);

g = 1;

return;

}

void cmp ( {a==b} ) {

Goto L1, L2

L1: assume( {a==b} );

{g==0} = T;

return;

L2: assume( !{a==b} );

{g==0} = F;

return;

}

decl {g==0} ;

main( {x==y} ) {

cmp( {x==y} );

assume( {g==0} );

assume( !{x==y} );

assert(0);

}

{x==y}

{g==0}

{a==b}

precision
Precision
  • For program P and E = {e1,...,en}, there exist two “ideal” abstractions:
    • Boolean(P,E) : most precise abstraction
    • Cartesian(P,E) : less precise abtraction, where each boolean variable is updated independently
    • [See Ball-Podelski-Rajamani, TACAS 00]
  • Theory:
    • with an “ideal” theorem prover, c2bp can compute Cartesian(P,E)
  • Practice:
    • c2bp computes a less precise abstraction than Cartesian(P,E)
    • we use Das/Dill’s technique to incrementally improve precision
    • with an “ideal” theorem prover, the combination of c2bp + Das/Dill can compute Boolean(P,E)
the slam process54
The SLAM Process

boolean

program

c2bp

prog. P

prog. P’

slic

bebop

SLIC rule

predicates

path

newton

bebop
Bebop
  • Model checker for boolean programs
  • Based on CFL reachability
    • [Sharir-Pnueli 81] [Reps-Sagiv-Horwitz 95]
  • Iterative addition of edges to graph
    • “path edges”: <entry,d1>  <v,d2>
    • “summary edges”: <call,d1>  <ret,d2>
symbolic cfl reachability
Symbolic CFL reachability
  • Partition path edges by their “target”
    • PE(v) = { <d1,d2> | <entry,d1>  <v,d2> }
  • What is <d1,d2> for boolean programs?
    • A bit-vector!
  • What is PE(v)?
    • A set of bit-vectors
  • Use a BDD (attached to v) to represent PE(v)
slide57

BDD at line [10] of cmp:

e2=e2’ & gz’=e2’

Read: “cmp leaves e2 unchanged and

sets gz to have the same final value as e2”

BDDs

void cmp ( e2 ) {

[5]Goto L1, L2

[6]L1: assume( e2 );

[7] gz = T; goto L3;

[8]L2: assume( !e2 );

[9]gz = F; goto L3

[10] L3: return;

}

  • Canonical representation of
    • boolean functions
    • set of (fixed-length) bitvectors
    • binary relations over finite domains
  • Efficient algorithms for common dataflow operations
    • transfer function
    • join/meet
    • subsumption test
slide58

decl gz ;

main( e ) {

[1] equal( e );

[2] assume( gz );

[3] assume( !e );

[4] assert(F);

}

gz=gz’& e=e’

e=e’& gz’=e’

e=e’ & gz’=1 & e’=1

e2=e

void cmp ( e2 ) {

[5]Goto L1, L2

[6]L1: assume( e2 );

[7] gz = T; goto L3;

[8]L2: assume( !e2 );

[9]gz = F; goto L3

[10] L3: return;

}

gz=gz’& e2=e2’

gz=gz’& e2=e2’& e2’=T

e2=e2’& e2’=T & gz’=T

gz=gz’& e2=e2’& e2’=F

e2=e2’& e2’=F & gz’=F

e2=e2’& gz’=e2’

bebop summary
Bebop: summary
  • Explicit representation of CFG
  • Implicit representation of path edges and summary edges
  • Generation of hierarchical error traces
  • Complexity: O(E * 2O(N))
    • E is the size of the CFG
    • N is the max. number of variables in scope
the slam process60
The SLAM Process

boolean

program

c2bp

prog. P

prog. P’

slic

bebop

SLIC rule

predicates

path

newton

newton
Newton
  • Given an error path p in boolean program B
    • is p a feasible path of the corresponding C program?
      • Yes: found an error
      • No: find predicates that explain the infeasibility
    • uses the same interfaces to the theorem provers as c2bp.
newton62
Newton
  • Execute path symbolically
  • Check conditions for inconsistency using theorem prover (satisfiability)
  • After detecting inconsistency:
    • minimize inconsistent conditions
    • traverse dependencies
    • obtain predicates
symbolic simulation for c
Symbolic simulation for C--

Domains

  • variables: names in the program
  • values: constants + symbols

State of the simulator has 3 components:

  • store: map from variables to values
  • conditions: predicates over symbols
  • history: past valuations of the store
symbolic simulation algorithm
Symbolic simulation Algorithm

Input: pathp

For each statement s in pdo

match s with

Assign(x,e):

let val = Eval(e) in

if(Store[x]) is defined then

History[x] := History[x]  Store[x]

Store[x] := val

Assume(e):

letval = Eval(e) in

Cond := Cond andval

let result = CheckConsistency(Cond) in

if (result == “inconsistent”) then

GenerateInconsistentPredicates()

End

Say “Path p is feasible”

symbolic simulation caveats
Symbolic Simulation: Caveats
  • Procedure calls
    • add a stack to the simulator
    • push and pop stack frames on calls and returns
    • implement mappings to keep values “in scope” at calls and returns
  • Dependencies
    • for each condition or store, keep track of which values where used to generate this value
    • traverse dependency during predicate generation
slide66

int g;

main(int x, int y){

cmp(x, y);

assume(!g);

assume(x != y)

assert(0);

}

void cmp (int a , int b) {

Goto L1, L2

L1: assume(a==b);

g = 0;

return;

L2: assume(a!=b);

g = 1;

return;

}

slide67

int g;

main(int x, int y){

cmp(x, y);

assume(!g);

assume(x != y)

assert(0);

}

void cmp (int a , int b) {

Goto L1, L2

L1: assume(a==b);

g = 0;

return;

L2: assume(a!=b);

g = 1;

return;

}

Global:

main:

x: X

y: Y

Conditions:

slide68

int g;

main(int x, int y){

cmp(x, y);

assume(!g);

assume(x != y)

assert(0);

}

void cmp (int a , int b) {

Goto L1, L2

L1: assume(a==b);

g = 0;

return;

L2: assume(a!=b);

g = 1;

return;

}

Global:

main:

x: X

y: Y

cmp:

a: A

b: B

Conditions:

Map:

X  A

Y  B

slide69

int g;

main(int x, int y){

cmp(x, y);

assume(!g);

assume(x != y)

assert(0);

}

void cmp (int a , int b) {

Goto L1, L2

L1: assume(a==b);

g = 0;

return;

L2: assume(a!=b);

g = 1;

return;

}

Global:

(6) g: 0

main:

x: X

y: Y

cmp:

a: A

b: B

Conditions:

(A == B) [3, 4]

Map:

X  A

Y  B

slide70

int g;

main(int x, int y){

cmp(x, y);

assume(!g);

assume(x != y)

assert(0);

}

void cmp (int a , int b) {

Goto L1, L2

L1: assume(a==b);

g = 0;

return;

L2: assume(a!=b);

g = 1;

return;

}

Global:

(6) g: 0

main:

x: X

y: Y

cmp:

a: A

b: B

Conditions:

(A == B) [3, 4]

(X == Y) [5]

Map:

X  A

Y  B

slide71

int g;

main(int x, int y){

cmp(x, y);

assume(!g);

assume(x != y)

assert(0);

}

void cmp (int a , int b) {

Goto L1, L2

L1: assume(a==b);

g = 0;

return;

L2: assume(a!=b);

g = 1;

return;

}

Global:

(6) g: 0

main:

x: X

y: Y

cmp:

a: A

b: B

Conditions:

(A == B) [3, 4]

(X == Y) [5]

(X != Y) [1, 2]

slide72

int g;

main(int x, int y){

cmp(x, y);

assume(!g);

assume(x != y)

assert(0);

}

void cmp (int a , int b) {

Goto L1, L2

L1: assume(a==b);

g = 0;

return;

L2: assume(a!=b);

g = 1;

return;

}

Global:

(6) g: 0

main:

x: X

y: Y

cmp:

a: A

b: B

Conditions:

(A == B) [3, 4]

(X == Y) [5]

(X != Y) [1, 2]

Contradictory!

slide73

int g;

main(int x, int y){

cmp(x, y);

assume(!g);

assume(x != y)

assert(0);

}

void cmp (int a , int b) {

Goto L1, L2

L1: assume(a==b);

g = 0;

return;

L2: assume(a!=b);

g = 1;

return;

}

Global:

(6) g: 0

main:

x: X

y: Y

cmp:

a: A

b: B

Conditions:

(A == B) [3, 4]

(X == Y) [5]

(X != Y) [1, 2]

Contradictory!

slide74

int g;

main(int x, int y){

cmp(x, y);

assume(!g);

assume(x != y)

assert(0);

}

void cmp (int a , int b) {

Goto L1, L2

L1: assume(a==b);

g = 0;

return;

L2: assume(a!=b);

g = 1;

return;

}

Predicates after simplification:

{ x == y, a == b }

slide76
C-

Types  ::= void | bool | int | ref 

Expressions e ::= c | x | e1 op e2 | &x | *x

LExpression l ::= x | *x

Declaration d ::=  x1,x2 ,…,xn

Statements s ::= skip | goto L1,L2 …Ln | L: s

| assume(e)

| l = e

| l = f (e1 ,e2 ,…,en)

| return x

| s1; s2 ;… ; sn

Procedures p ::=f (x1: 1,x2 : 2,…,xn : n )

Program g ::= d1 d2 … dn p1 p2 … pn

two problems
Two Problems
  • Extending SLAM tools for pointers
  • Dealing with imprecision of alias analysis
pointers and slam
Pointers and SLAM
  • With pointers, C supports call by reference
    • Strictly speaking, C supports only call by value
    • With pointers and the address-of operator, one can simulate call-by-reference
  • Boolean programs support only call-by-value-result
    • SLAM mimics call-by-reference with call-by-value-result
  • Extra complications:
    • address operator (&) in C
    • multiple levels of pointer dereference in C
what changes with pointers
What changes with pointers?
  • C2bp
    • abstracting assignments
    • abstracting procedure returns
  • Newton
    • simulation needs to handle pointer accesses
    • need to copy local heap across scopes to match Bebop’s semantics
    • need to refine imprecise alias analysis using predicates
  • Bebop
    • remains unchanged!
assignments pointers
Assignments + Pointers

Statement in P: Predicates in E:

*p = 3 {x==5}

Weakest Precondition:

WP( *p=3 , x==5 ) = x==5What if *p and x alias?

Correct Weakest Precondition:

(p==&x and 3==5) or (p!=&x and x==5)

We use Das’s pointer analysis [PLDI 2000] to prune

disjuncts representing infeasible alias scenarios.

abstracting procedure return
Abstracting Procedure Return
  • Need to account for
    • lhs of procedure call
    • mixed predicates
    • side-effects of procedure
  • Boolean programs support only call-by-value-result
    • C2bp models all side-effects using return processing
abstracting procedure returns
Abstracting Procedure Returns
  • Let a be an actual at call-site P(…)
    • pre(a) = the value of abefore transition to P
  • Let f be a formal of a procedure P
    • pre(f) = the value of f upon entry to P
slide83

predicate

call/return relation

call/return assign

  • int R (int f) {
  • int r = f+1;
  • f = 0;
  • return r;
  • }

Q() {

int x = 1;

x = R(x)

}

f = x

{f==pre(f)}

{r==pre(f)+1}

{x==1}

{x==2}

pre(f) == pre(x)

x = r

WP(f=x, f==pre(f) ) = x==pre(f)

x==pre(f) is true at the call to R

WP(x=r, x==2) = r==2

pre(f)==pre(x)andpre(x)==1andr==pre(f)+1impliesr==2

{x==1}

s

Q() {

{x==1},{x==2} = T,F;

  • bool R ( {f==pre(f)} ) {
  • {r==pre(f)+1} = {f==pre(f)};
  • {f==pre(f)} = *;
  • return {r==pre(f)+1};
  • }

s = R(T);

{x==2} = s & {x==1};

}

slide84

predicate

call/return relation

call/return assign

  • int R (int f) {
  • int r = f+1;
  • f = 0;
  • return r;
  • }

Q() {

int x = 1;

x = R(x)

}

f = x

{f==pre(f)}

{r==pre(f)+1}

{x==1}

{x==2}

pre(f) == pre(x)

x = r

WP(f=x, f==pre(f) ) = x==pre(f)

x==pre(f) is true at the call to R

WP(x=r, x==2) = r==2

pre(f)==pre(x)andpre(x)==1andr==pre(f)+1impliesr==2

{x==1}

s

Q() {

{x==1},{x==2} = T,F;

  • bool R ( {f==pre(f)} ) {
  • {r==pre(f)+1} = {f==pre(f)};
  • {f==pre(f)} = *;
  • return {r==pre(f)+1};
  • }

s = R(T);

{x==1}, {x==2} = *, s & {x==1};

}

extending pre states
Extending Pre-states
  • Suppose formal parameter is a pointer
    • eg. P(int *f)
  • pre( *f )
    • value of *f upon entry to P
    • can’t change during P
  • * pre( f )
    • value of dereference of pre( f )
    • can change during P
slide86

predicate

call/return relation

call/return assign

{a==pre(a)}

{*pre(a)==pre(*a)}

Q() {

int x = 1;

R(&x);

}

  • int R (int *a) {
  • *a = *a+1;
  • }

{x==1}

{x==2}

a = &x

pre(a) = &x

{*pre(a)=pre(*a)+1}

pre(x)==1andpre(*a)==pre(x)and*pre(a)==pre(*a)+1andpre(a)==&x

impliesx==2

{x==1}

s

Q() {

{x==1},{x==2} = T,F;

  • bool R ( {a==pre(a)}, {*pre(a)==pre(*a)} ) {
  • {*pre(a)==pre(*a)+1} =
  • {a==pre(a)} & {*pre(a)==pre(*a)};
  • return {*pre(a)==pre(*a)+1};
  • }

s = R(T,T);

{x==2} = s & {x==1};

}

newton what changes with pointers
Newton: what changes with pointers?
  • Simulation needs to handle pointer accesses
  • Need to copy local heap across scopes to match Bebop’s semantics
slide88

main(int *x){

assume(*x < 5);

foo(x);

}

void foo (int *a) {

assume(*a > 5);

assert(0);

}

slide89

main(int *x){

assume(*x < 5);

foo(x);

}

void foo (int *a) {

assume(*a > 5);

assert(0);

}

Predicates after simplification:

*x < 5 , *a < 5, *a > 5

main:

x: X

*X: Y [1]

foo:

a: A

*A: B [3]

Conditions:

(Y< 5) [1,2]

(B < 5) [3,4,5]

(B > 5) [3,4]

Contradictory!

slam imprecision due to alias imprecision flow insensitivity

{x==0}

SLAM Imprecision due to Alias Imprecision (Flow Insensitivity)

{x==0} = T;

skip;

skip;

{x==0} = *;

assume( !{x==0} );

skip;

x = 0;

y = 0;

p = &y

*p = *p + 1;

assume(x!=0);

p = &x;

Pts-to(p)

=

{ &x, &y}

newton path is infeasible

{x==0} = T;

skip;

skip;

{x==0} = *;

assume(!{x==0} );

skip;

x = 0;

y = 0;

p = &y

*p = *p + 1;

assume(x!=0);

p = &x;

Newton: Path is Infeasible

x = 0;

y = 0;

p = &y

if (p == &x)

x = x + 1;

else

y = y + 1;

assume(x!=0);

p = &x;

consider values in abstract trace

{x==0} = T;

skip;

skip;

{x==0} = *;

assume(!{x==0} );

skip;

x = 0;

y = 0;

p = &y

*p = *p + 1;

assume(x!=0);

p = &x;

Consider values in abstract trace

{x==0} is true

INCONSISTENT

{x==0} is false

consider values in abstract trace93

{x==0} = T;

skip;

skip;

{x==0} = *;

assume(!{x==0} );

skip;

x = 0;

y = 0;

p = &y

*p = *p + 1;

assume(x!=0);

p = &x;

Consider values in abstract trace

WP(*p = *p +1, !(x==0) )

= ((p == &x) and !(x==-1)) or ((p != &x) and !(x==0))

(p!=&x) gets added as a predicate

what changes with pointers94
What changes with pointers?
  • C2bp
    • abstracting assignments
    • abstracting procedure returns
  • Newton
    • simulation needs to handle pointer accesses
    • need to copy local heap across scopes to match Bebop’s semantics
    • need to refine imprecise alias analysis using predicates
  • Bebop
    • remains unchanged!
what worked well
What worked well?
  • Specific domain problem
  • Safety properties
  • Shoulders & synergies
  • Separation of concerns
  • Summer interns & visitors
    • Sagar Chaki, Todd Millstein, Rupak Majumdar (2000)
    • Satyaki Das, Wes Weimer, Robby (2001)
    • Jakob Lichtenberg, Mayur Naik (2002)
    • Giorgio Delzanno, Andreas Podelski, Stefan Schwoon
  • Windows Partners
    • Byron Cook, Vladimir Levin, Abdullah Ustuner
future work
Future Work
  • Concurrency
    • SLAM analyzes drivers one thread at a time
    • Work in progress to analyze interleavings between threads
  • Rules and environment-models
    • Large scale development or rules and environment-models is a challenge
    • How can we simplify and manage development of rules?
  • Modeling C semantics faithfully
  • Theory:
    • Prove that SLAM will make progress on any property and any program
    • Identify classes of programs and properties on which SLAM will terminate
further reading
Further Reading

See papers, slides from:

http://research.microsoft.com/slam